diff options
-rw-r--r-- | bug71039.patch | 300 | ||||
-rw-r--r-- | bug71323.patch | 1491 | ||||
-rw-r--r-- | bug71335.patch | 66 | ||||
-rw-r--r-- | bug71354.patch | 28 | ||||
-rw-r--r-- | bug71391.patch | 31 | ||||
-rw-r--r-- | bug71459.patch | 65 | ||||
-rw-r--r-- | bug71488.patch | 80 | ||||
-rw-r--r-- | failed.txt | 2 | ||||
-rw-r--r-- | pcre838.patch | 6665 | ||||
-rw-r--r-- | php54.spec | 31 |
10 files changed, 8756 insertions, 3 deletions
diff --git a/bug71039.patch b/bug71039.patch new file mode 100644 index 0000000..343364c --- /dev/null +++ b/bug71039.patch @@ -0,0 +1,300 @@ +Backported from 5.5 for 5.4 by Remi Collet + +From f4d7bbf4ace4ea21c8f95c2d1177bd56a21b86b9 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Thu, 28 Jan 2016 13:45:43 +0100 +Subject: [PATCH] backport the escapeshell* functions hardening branch + +--- + ext/standard/basic_functions.c | 1 + + ext/standard/exec.c | 76 +++++++++++++++++++++++++++++++++++++++--- + ext/standard/exec.h | 1 + + 3 files changed, 73 insertions(+), 5 deletions(-) + +diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c +index f8cb91e..50b6bc7 100644 +--- a/ext/standard/basic_functions.c ++++ b/ext/standard/basic_functions.c +@@ -3613,6 +3613,7 @@ + #ifdef PHP_CAN_SUPPORT_PROC_OPEN + PHP_MINIT(proc_open)(INIT_FUNC_ARGS_PASSTHRU); + #endif ++ PHP_MINIT(exec)(INIT_FUNC_ARGS_PASSTHRU); + + PHP_MINIT(user_streams)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(imagetypes)(INIT_FUNC_ARGS_PASSTHRU); +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 66d4537..461bef4 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -46,10 +46,42 @@ + #include <fcntl.h> + #endif + +-#if HAVE_NICE && HAVE_UNISTD_H ++#if HAVE_UNISTD_H + #include <unistd.h> + #endif + ++#ifdef PHP_WIN32 ++# include "win32/php_stdint.h" ++#else ++# if HAVE_INTTYPES_H ++# include <inttypes.h> ++# elif HAVE_STDINT_H ++# include <stdint.h> ++# endif ++#endif ++ ++static int cmd_max_len; ++ ++/* {{{ PHP_MINIT_FUNCTION(exec) */ ++PHP_MINIT_FUNCTION(exec) ++{ ++#ifdef _SC_ARG_MAX ++ cmd_max_len = sysconf(_SC_ARG_MAX); ++#elif defined(ARG_MAX) ++ cmd_max_len = ARG_MAX; ++#elif defined(PHP_WIN32) ++ /* Executed commands will run through cmd.exe. As long as it's the case, ++ it's just the constant limit.*/ ++ cmd_max_len = 8192; ++#else ++ /* This is just an arbitrary value for the fallback case. */ ++ cmd_max_len = 4096; ++#endif ++ ++ return SUCCESS; ++} ++/* }}} */ ++ + /* {{{ php_exec + * If type==0, only last line of output is returned (exec) + * If type==1, all lines will be printed and last lined returned (system) +@@ -244,13 +276,20 @@ PHP_FUNCTION(passthru) + */ + PHPAPI char *php_escape_shell_cmd(char *str) + { +- register int x, y, l = strlen(str); ++ register int x, y; ++ size_t l = strlen(str); ++ uint64_t estimate = (2 * (uint64_t)l) + 1; + char *cmd; + char *p = NULL; +- size_t estimate = (2 * l) + 1; + + TSRMLS_FETCH(); + ++ /* max command line length - two single quotes - \0 byte length */ ++ if (l > cmd_max_len - 2 - 1) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Command exceeds the allowed length of %d bytes", cmd_max_len); ++ return NULL; ++ } ++ + cmd = safe_emalloc(2, l, 1); + + for (x = 0, y = 0; x < l; x++) { +@@ -322,6 +361,12 @@ PHPAPI char *php_escape_shell_cmd(char *str) + } + cmd[y] = '\0'; + ++ if (y - 1 > cmd_max_len) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped command exceeds the allowed length of %d bytes", cmd_max_len); ++ efree(cmd); ++ return NULL; ++ } ++ + if ((estimate - y) > 4096) { + /* realloc if the estimate was way overill + * Arbitrary cutoff point of 4096 */ +@@ -336,12 +381,19 @@ PHPAPI char *php_escape_shell_cmd(char *str) + */ + PHPAPI char *php_escape_shell_arg(char *str) + { +- int x, y = 0, l = strlen(str); ++ int x, y = 0; ++ size_t l = strlen(str); + char *cmd; +- size_t estimate = (4 * l) + 3; ++ uint64_t estimate = (4 * (uint64_t)l) + 3; + + TSRMLS_FETCH(); + ++ /* max command line length - two single quotes - \0 byte length */ ++ if (l > cmd_max_len - 2 - 1) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Argument exceeds the allowed length of %d bytes", cmd_max_len); ++ return NULL; ++ } ++ + cmd = safe_emalloc(4, l, 3); /* worst case */ + + #ifdef PHP_WIN32 +@@ -396,6 +448,12 @@ PHPAPI char *php_escape_shell_arg(char *str) + #endif + cmd[y] = '\0'; + ++ if (y - 1 > cmd_max_len) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Escaped argument exceeds the allowed length of %d bytes", cmd_max_len); ++ efree(cmd); ++ return NULL; ++ } ++ + if ((estimate - y) > 4096) { + /* realloc if the estimate was way overill + * Arbitrary cutoff point of 4096 */ +@@ -418,6 +476,10 @@ PHP_FUNCTION(escapeshellcmd) + } + + if (command_len) { ++ if (command_len != strlen(command)) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes"); ++ return; ++ } + cmd = php_escape_shell_cmd(command); + RETVAL_STRING(cmd, 0); + } else { +@@ -439,6 +501,10 @@ PHP_FUNCTION(escapeshellarg) + } + + if (argument) { ++ if (argument_len != strlen(argument)) { ++ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Input string contains NULL bytes"); ++ return; ++ } + cmd = php_escape_shell_arg(argument); + RETVAL_STRING(cmd, 0); + } +diff --git a/ext/standard/exec.h b/ext/standard/exec.h +index 399325c..b106838 100644 +--- a/ext/standard/exec.h ++++ b/ext/standard/exec.h +@@ -33,6 +33,7 @@ PHP_FUNCTION(proc_close); + PHP_FUNCTION(proc_terminate); + PHP_FUNCTION(proc_nice); + PHP_MINIT_FUNCTION(proc_open); ++PHP_MINIT_FUNCTION(exec); + + PHPAPI char *php_escape_shell_cmd(char *); + PHPAPI char *php_escape_shell_arg(char *); +From 828364e59ca08c2ff3328a648522f9eb05ebbaa3 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Thu, 28 Jan 2016 13:27:26 +0100 +Subject: [PATCH] add tests + +--- + .../tests/general_functions/escapeshellarg_bug71039.phpt | 10 ++++++++++ + .../tests/general_functions/escapeshellarg_bug71270.phpt | 12 ++++++++++++ + .../tests/general_functions/escapeshellcmd_bug71039.phpt | 10 ++++++++++ + .../tests/general_functions/escapeshellcmd_bug71270.phpt | 12 ++++++++++++ + 4 files changed, 44 insertions(+) + create mode 100644 ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt + create mode 100644 ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt + +diff --git a/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt b/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt +new file mode 100644 +index 0000000..cbb3f6f +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellarg_bug71039.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Test escapeshellarg() string with \0 bytes ++--FILE-- ++<?php ++escapeshellarg("hello\0world"); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellarg(): Input string contains NULL bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt b/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt +new file mode 100644 +index 0000000..c57da36 +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellarg_bug71270.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Test escapeshellarg() allowed argument length ++--FILE-- ++<?php ++ini_set('memory_limit', -1); ++$var_2 = str_repeat('A', 1024*1024*64); ++escapeshellarg($var_2); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellarg(): Argument exceeds the allowed length of %d bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt b/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt +new file mode 100644 +index 0000000..0a4d7ea +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellcmd_bug71039.phpt +@@ -0,0 +1,10 @@ ++--TEST-- ++Test escapeshellcmd() string with \0 bytes ++--FILE-- ++<?php ++escapeshellcmd("hello\0world"); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellcmd(): Input string contains NULL bytes in %s on line %d +diff --git a/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt b/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt +new file mode 100644 +index 0000000..4686193 +--- /dev/null ++++ b/ext/standard/tests/general_functions/escapeshellcmd_bug71270.phpt +@@ -0,0 +1,12 @@ ++--TEST-- ++Test escapeshellcmd() allowed argument length ++--FILE-- ++<?php ++ini_set('memory_limit', -1); ++$var_2 = str_repeat('A', 1024*1024*64); ++escapeshellcmd($var_2); ++ ++?> ++===DONE=== ++--EXPECTF-- ++Fatal error: escapeshellcmd(): Command exceeds the allowed length of %d bytes in %s on line %d +From 377d353c9f8aad6f79f3cf84aad3e2f6d65fa456 Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Tue, 2 Feb 2016 14:19:10 +0100 +Subject: [PATCH] add error check to sysconf call + +--- + ext/standard/exec.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/ext/standard/exec.c b/ext/standard/exec.c +index 461bef4..329066e 100644 +--- a/ext/standard/exec.c ++++ b/ext/standard/exec.c +@@ -50,6 +50,10 @@ + #include <unistd.h> + #endif + ++#if HAVE_LIMITS_H ++#include <limits.h> ++#endif ++ + #ifdef PHP_WIN32 + # include "win32/php_stdint.h" + #else +@@ -67,6 +71,13 @@ PHP_MINIT_FUNCTION(exec) + { + #ifdef _SC_ARG_MAX + cmd_max_len = sysconf(_SC_ARG_MAX); ++ if (-1 == cmd_max_len) { ++#ifdef _POSIX_ARG_MAX ++ cmd_max_len = _POSIX_ARG_MAX; ++#else ++ cmd_max_len = 4096; ++#endif ++ } + #elif defined(ARG_MAX) + cmd_max_len = ARG_MAX; + #elif defined(PHP_WIN32) diff --git a/bug71323.patch b/bug71323.patch new file mode 100644 index 0000000..51aa715 --- /dev/null +++ b/bug71323.patch @@ -0,0 +1,1491 @@ +Backported from 5.5 for 5.4 by Remi Collet + +From 6297a117d77fa3a0df2e21ca926a92c231819cd5 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sat, 16 Jan 2016 22:10:54 -0800 +Subject: [PATCH] Fixed bug #71323 - Output of stream_get_meta_data can be + falsified by its input + +--- + ext/standard/streamsfuncs.c | 20 ++-- + ext/standard/tests/streams/bug71323.phpt | 31 ++++++ + .../streams/stream_get_meta_data_dir_basic.phpt | 16 ++-- + .../streams/stream_get_meta_data_file_basic.phpt | 12 +-- + .../stream_get_meta_data_file_variation1.phpt | 104 ++++++++++----------- + .../stream_get_meta_data_file_variation2.phpt | 46 ++++----- + .../stream_get_meta_data_file_variation4.phpt | 20 ++-- + .../stream_get_meta_data_file_variation5.phpt | 24 ++--- + .../stream_get_meta_data_process_basic.phpt | 12 +-- + .../streams/stream_get_meta_data_socket_basic.phpt | 12 +-- + .../stream_get_meta_data_socket_variation1.phpt | 44 ++++----- + .../stream_get_meta_data_socket_variation2.phpt | 46 ++++----- + .../stream_get_meta_data_socket_variation3.phpt | 36 +++---- + .../stream_get_meta_data_socket_variation4.phpt | 34 +++---- + main/streams/memory.c | 30 +++--- + 15 files changed, 260 insertions(+), 227 deletions(-) + create mode 100644 ext/standard/tests/streams/bug71323.phpt + +diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c +index 4c2837e..d11f111 100644 +--- a/ext/standard/streamsfuncs.c ++++ b/ext/standard/streamsfuncs.c +@@ -496,6 +496,12 @@ PHP_FUNCTION(stream_get_meta_data) + + array_init(return_value); + ++ if (!php_stream_populate_meta_data(stream, return_value)) { ++ add_assoc_bool(return_value, "timed_out", 0); ++ add_assoc_bool(return_value, "blocked", 1); ++ add_assoc_bool(return_value, "eof", php_stream_eof(stream)); ++ } ++ + if (stream->wrapperdata) { + MAKE_STD_ZVAL(newval); + MAKE_COPY_ZVAL(&stream->wrapperdata, newval); +@@ -531,12 +537,6 @@ PHP_FUNCTION(stream_get_meta_data) + add_assoc_string(return_value, "uri", stream->orig_path, 1); + } + +- if (!php_stream_populate_meta_data(stream, return_value)) { +- add_assoc_bool(return_value, "timed_out", 0); +- add_assoc_bool(return_value, "blocked", 1); +- add_assoc_bool(return_value, "eof", php_stream_eof(stream)); +- } +- + } + /* }}} */ + +diff --git a/ext/standard/tests/streams/bug71323.phpt b/ext/standard/tests/streams/bug71323.phpt +new file mode 100644 +index 0000000..dfe0bd8 +--- /dev/null ++++ b/ext/standard/tests/streams/bug71323.phpt +@@ -0,0 +1,31 @@ ++--TEST-- ++Bug #71323: Output of stream_get_meta_data can be falsified by its input ++--FILE-- ++<?php ++$file = 'data:text/plain;z=y;uri=eviluri;mediatype=wut?;mediatype2=hello,somedata'; ++$meta = stream_get_meta_data(fopen($file, "r")); ++var_dump($meta); ++?> ++--EXPECTF-- ++array(10) { ++ ["mediatype"]=> ++ string(10) "text/plain" ++ ["z"]=> ++ string(1) "y" ++ ["uri"]=> ++ string(72) "data:text/plain;z=y;uri=eviluri;mediatype=wut?;mediatype2=hello,somedata" ++ ["mediatype2"]=> ++ string(5) "hello" ++ ["base64"]=> ++ bool(false) ++ ["wrapper_type"]=> ++ string(7) "RFC2397" ++ ["stream_type"]=> ++ string(7) "RFC2397" ++ ["mode"]=> ++ string(1) "r" ++ ["unread_bytes"]=> ++ int(0) ++ ["seekable"]=> ++ bool(true) ++} +diff --git a/ext/standard/tests/streams/stream_get_meta_data_dir_basic.phpt b/ext/standard/tests/streams/stream_get_meta_data_dir_basic.phpt +index f46c8fd..6658d69 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_dir_basic.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_dir_basic.phpt +@@ -13,6 +13,12 @@ var_dump(stream_get_meta_data($dirObject->handle)); + ?> + --EXPECT-- + array(8) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -23,14 +29,14 @@ array(8) { + int(0) + ["seekable"]=> + bool(true) ++} ++array(8) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(8) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -41,10 +47,4 @@ array(8) { + int(0) + ["seekable"]=> + bool(true) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_basic.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_basic.phpt +index 4758c75..bad5987 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_file_basic.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_file_basic.phpt +@@ -12,6 +12,12 @@ fclose($fp); + ?> + --EXPECTF-- + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -24,10 +30,4 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%sstream_get_meta_data_file_basic.php" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_variation1.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_variation1.phpt +index 572653e..d54eb04 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_file_variation1.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_file_variation1.phpt +@@ -29,6 +29,12 @@ unlink($filename); + ?> + --EXPECTF-- + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -41,14 +47,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -61,14 +67,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -81,14 +87,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -101,14 +107,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -121,14 +127,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -141,14 +147,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -161,14 +167,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -181,14 +187,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -201,14 +207,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -221,14 +227,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -241,14 +247,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -261,14 +267,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -281,14 +287,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -301,14 +307,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -321,14 +327,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -341,14 +347,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -361,14 +367,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -381,14 +387,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -401,14 +407,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -421,14 +427,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -441,14 +447,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -461,14 +467,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -481,14 +487,14 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -501,10 +507,4 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_variation2.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_variation2.phpt +index d186cb7..6b3fde2 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_file_variation2.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_file_variation2.phpt +@@ -43,6 +43,12 @@ unlink($filename); + --EXPECTF-- + Write some data to the file: + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -55,12 +61,6 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + +@@ -68,6 +68,12 @@ Read a line of the file, causing data to be buffered: + string(15) "a line of data + " + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -80,17 +86,17 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" ++} ++ ++ ++Read 20 bytes from the file: ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Read 20 bytes from the file: +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -103,17 +109,17 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + + Read entire file: + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(true) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -126,10 +132,4 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s.tmp" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(true) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_variation4.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_variation4.phpt +index c51d9bd..46a5ba5 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_file_variation4.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_file_variation4.phpt +@@ -28,6 +28,12 @@ unlink($filename); + --EXPECTF-- + Create a file: + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -40,16 +46,16 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "File://%sstream_get_meta_data_file_variation4.php.tmp" ++} ++ ++Change to file's directory and open with a relative path: ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +-Change to file's directory and open with a relative path: +-array(9) { + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -62,10 +68,4 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "stream_get_meta_data_file_variation4.php.tmp" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_file_variation5.phpt b/ext/standard/tests/streams/stream_get_meta_data_file_variation5.phpt +index 386b92f..22fcee4 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_file_variation5.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_file_variation5.phpt +@@ -33,6 +33,12 @@ unlink($filename); + --EXPECTF-- + Write some data to the file: + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -45,17 +51,17 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + + Read entire file: + array(9) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(true) + ["wrapper_type"]=> + string(9) "plainfile" + ["stream_type"]=> +@@ -68,10 +74,4 @@ array(9) { + bool(true) + ["uri"]=> + string(%i) "%s" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(true) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_process_basic.phpt b/ext/standard/tests/streams/stream_get_meta_data_process_basic.phpt +index 3f4dfbc..b7ab37c 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_process_basic.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_process_basic.phpt +@@ -18,6 +18,12 @@ echo "Done"; + ?> + --EXPECT-- + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(5) "STDIO" + ["mode"]=> +@@ -26,11 +32,5 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + Done +diff --git a/ext/standard/tests/streams/stream_get_meta_data_socket_basic.phpt b/ext/standard/tests/streams/stream_get_meta_data_socket_basic.phpt +index 8605611..c5136ab 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_socket_basic.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_socket_basic.phpt +@@ -10,6 +10,12 @@ fclose($tcp_socket); + ?> + --EXPECTF-- + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -18,10 +24,4 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt b/ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt +index 16b38d9..18d6a4a 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt +@@ -39,6 +39,12 @@ var_dump(stream_get_meta_data($client)); + --EXPECTF-- + Write some data: + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -47,17 +53,17 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) ++} ++ ++ ++Read a line from the client, causing data to be buffered: ++array(7) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Read a line from the client, causing data to be buffered: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -66,17 +72,17 @@ array(7) { + int(15) + ["seekable"]=> + bool(false) ++} ++ ++ ++Read 3 bytes of data from the client: ++array(7) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Read 3 bytes of data from the client: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -85,17 +91,17 @@ array(7) { + int(12) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + + Close the server side socket and read the remaining data from the client: + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(true) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -104,10 +110,4 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(true) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt b/ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt +index d30fec7..712a661 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt +@@ -37,25 +37,12 @@ fclose($server); + ?> + --EXPECTF-- + array(7) { +- ["stream_type"]=> +- string(%d) "tcp_socke%s" +- ["mode"]=> +- string(2) "r+" +- ["unread_bytes"]=> +- int(0) +- ["seekable"]=> +- bool(false) + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Set a timeout on the client and attempt a read: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -64,17 +51,17 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) ++} ++ ++ ++Set a timeout on the client and attempt a read: ++array(7) { + ["timed_out"]=> + bool(true) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Write some data from the server: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -83,17 +70,17 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) ++} ++ ++ ++Write some data from the server: ++array(7) { + ["timed_out"]=> + bool(true) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Read some data from the client: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -102,10 +89,23 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) ++} ++ ++ ++Read some data from the client: ++array(7) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) ++ ["stream_type"]=> ++ string(%d) "tcp_socke%s" ++ ["mode"]=> ++ string(2) "r+" ++ ["unread_bytes"]=> ++ int(0) ++ ["seekable"]=> ++ bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt b/ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt +index 0b079cc..4198973 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt +@@ -32,6 +32,12 @@ fclose($server); + ?> + --EXPECTF-- + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -40,18 +46,18 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + + Set blocking to false: + bool(true) + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(false) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -60,18 +66,18 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(false) +- ["eof"]=> +- bool(false) + } + + + Set blocking to true: + bool(true) + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -80,10 +86,4 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt b/ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt +index f9ef747..50d7ddf 100644 +--- a/ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt ++++ b/ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt +@@ -37,6 +37,12 @@ fclose($client); + --EXPECTF-- + Write some data: + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -45,17 +51,17 @@ array(7) { + int(%i) + ["seekable"]=> + bool(false) ++} ++ ++ ++Read a line from the client: ++array(7) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +- +-Read a line from the client: +-array(7) { + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -64,17 +70,17 @@ array(7) { + int(%i) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + + + Close the server side socket and read the remaining data from the client: + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(true) + ["stream_type"]=> + string(%d) "tcp_socke%s" + ["mode"]=> +@@ -83,10 +89,4 @@ array(7) { + int(%i) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(true) + } +diff --git a/main/streams/memory.c b/main/streams/memory.c +index d0f2511..eb31db3 100644 +--- a/main/streams/memory.c ++++ b/main/streams/memory.c +@@ -674,7 +674,9 @@ static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, cha + plen = sep - path; + vlen = (semi ? semi - sep : mlen - plen) - 1 /* '=' */; + key = estrndup(path, plen); +- add_assoc_stringl_ex(meta, key, plen + 1, sep + 1, vlen, 1); ++ if (plen != sizeof("mediatype")-1 || memcmp(key, "mediatype", sizeof("mediatype")-1)) { ++ add_assoc_stringl_ex(meta, key, plen + 1, sep + 1, vlen, 1); ++ } + efree(key); + plen += vlen + 1; + mlen -= plen; +From 2a7d8c0a06de8123034b136b0c717576b6e36fae Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Mon, 1 Feb 2016 18:58:02 -0800 +Subject: [PATCH] fix tests + +--- + ext/standard/tests/file/stream_rfc2397_002.phpt | 56 +++++++++++----------- + .../tests/network/socket_get_status_basic.phpt | 12 ++--- + ext/zip/tests/stream_meta_data.phpt | 16 +++---- + ext/zlib/tests/zlib_wrapper_meta_data_basic.phpt | 20 ++++---- + 4 files changed, 52 insertions(+), 52 deletions(-) + +diff --git a/ext/standard/tests/file/stream_rfc2397_002.phpt b/ext/standard/tests/file/stream_rfc2397_002.phpt +index 980863b..1dce5ad 100644 +--- a/ext/standard/tests/file/stream_rfc2397_002.phpt ++++ b/ext/standard/tests/file/stream_rfc2397_002.phpt +@@ -34,6 +34,8 @@ foreach($streams as $stream) + <?php exit(0); ?> + --EXPECTF-- + array(7) { ++ ["base64"]=> ++ bool(false) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -46,8 +48,6 @@ array(7) { + bool(true) + ["uri"]=> + string(8) "data://," +- ["base64"]=> +- bool(false) + } + NULL + +@@ -55,6 +55,8 @@ Warning: fopen(data://): failed to open stream: rfc2397: no comma in URL in %sst + NULL + NULL + array(7) { ++ ["base64"]=> ++ bool(true) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -67,8 +69,6 @@ array(7) { + bool(true) + ["uri"]=> + string(15) "data://;base64," +- ["base64"]=> +- bool(true) + } + NULL + +@@ -84,6 +84,10 @@ Warning: fopen(data://foo=bar,): failed to open stream: rfc2397: illegal media t + NULL + NULL + array(8) { ++ ["mediatype"]=> ++ string(10) "text/plain" ++ ["base64"]=> ++ bool(false) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -96,10 +100,6 @@ array(8) { + bool(true) + ["uri"]=> + string(18) "data://text/plain," +- ["mediatype"]=> +- string(10) "text/plain" +- ["base64"]=> +- bool(false) + } + NULL + +@@ -107,6 +107,12 @@ Warning: fopen(data://text/plain;foo,): failed to open stream: rfc2397: illegal + NULL + NULL + array(9) { ++ ["mediatype"]=> ++ string(10) "text/plain" ++ ["foo"]=> ++ string(3) "bar" ++ ["base64"]=> ++ bool(false) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -119,12 +125,6 @@ array(9) { + bool(true) + ["uri"]=> + string(26) "data://text/plain;foo=bar," +- ["mediatype"]=> +- string(10) "text/plain" +- ["foo"]=> +- string(3) "bar" +- ["base64"]=> +- bool(false) + } + string(3) "bar" + +@@ -132,6 +132,12 @@ Warning: fopen(data://text/plain;foo=bar;bla,): failed to open stream: rfc2397: + NULL + NULL + array(9) { ++ ["mediatype"]=> ++ string(10) "text/plain" ++ ["foo"]=> ++ string(3) "bar" ++ ["base64"]=> ++ bool(true) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -144,12 +150,6 @@ array(9) { + bool(true) + ["uri"]=> + string(33) "data://text/plain;foo=bar;base64," +- ["mediatype"]=> +- string(10) "text/plain" +- ["foo"]=> +- string(3) "bar" +- ["base64"]=> +- bool(true) + } + string(3) "bar" + +@@ -157,6 +157,14 @@ Warning: fopen(data://text/plain;foo=bar;bar=baz): failed to open stream: rfc239 + NULL + NULL + array(10) { ++ ["mediatype"]=> ++ string(10) "text/plain" ++ ["foo"]=> ++ string(3) "bar" ++ ["bar"]=> ++ string(3) "baz" ++ ["base64"]=> ++ bool(false) + ["wrapper_type"]=> + string(7) "RFC2397" + ["stream_type"]=> +@@ -169,14 +177,6 @@ array(10) { + bool(true) + ["uri"]=> + string(34) "data://text/plain;foo=bar;bar=baz," +- ["mediatype"]=> +- string(10) "text/plain" +- ["foo"]=> +- string(3) "bar" +- ["bar"]=> +- string(3) "baz" +- ["base64"]=> +- bool(false) + } + string(3) "bar" + ===DONE=== +diff --git a/ext/standard/tests/network/socket_get_status_basic.phpt b/ext/standard/tests/network/socket_get_status_basic.phpt +index 46215f9..32a8d9c 100644 +--- a/ext/standard/tests/network/socket_get_status_basic.phpt ++++ b/ext/standard/tests/network/socket_get_status_basic.phpt +@@ -18,6 +18,12 @@ fclose($server); + ?> + --EXPECTF-- + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(%d) "tcp_socket%S" + ["mode"]=> +@@ -26,10 +32,4 @@ array(7) { + int(0) + ["seekable"]=> + bool(false) +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/zip/tests/stream_meta_data.phpt b/ext/zip/tests/stream_meta_data.phpt +index bd08098..63f720a 100644 +--- a/ext/zip/tests/stream_meta_data.phpt ++++ b/ext/zip/tests/stream_meta_data.phpt +@@ -35,6 +35,12 @@ fclose($fp); + ?> + --EXPECTF-- + array(8) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(3) "zip" + ["mode"]=> +@@ -45,14 +51,14 @@ array(8) { + bool(false) + ["uri"]=> + string(3) "foo" ++} ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +-array(9) { + ["wrapper_type"]=> + string(11) "zip wrapper" + ["stream_type"]=> +@@ -65,10 +71,4 @@ array(9) { + bool(false) + ["uri"]=> + string(%d) "zip://%stest_with_comment.zip#foo" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } +diff --git a/ext/zlib/tests/zlib_wrapper_meta_data_basic.phpt b/ext/zlib/tests/zlib_wrapper_meta_data_basic.phpt +index 2f76b46..a9d208e 100644 +--- a/ext/zlib/tests/zlib_wrapper_meta_data_basic.phpt ++++ b/ext/zlib/tests/zlib_wrapper_meta_data_basic.phpt +@@ -25,6 +25,12 @@ gzclose($h); + --EXPECTF-- + no wrapper + array(7) { ++ ["timed_out"]=> ++ bool(false) ++ ["blocked"]=> ++ bool(true) ++ ["eof"]=> ++ bool(false) + ["stream_type"]=> + string(4) "ZLIB" + ["mode"]=> +@@ -33,16 +39,16 @@ array(7) { + int(0) + ["seekable"]=> + bool(true) ++} ++ ++with wrapper ++array(9) { + ["timed_out"]=> + bool(false) + ["blocked"]=> + bool(true) + ["eof"]=> + bool(false) +-} +- +-with wrapper +-array(9) { + ["wrapper_type"]=> + string(4) "ZLIB" + ["stream_type"]=> +@@ -55,11 +61,5 @@ array(9) { + bool(true) + ["uri"]=> + string(%d) "compress.zlib://%s/004.txt.gz" +- ["timed_out"]=> +- bool(false) +- ["blocked"]=> +- bool(true) +- ["eof"]=> +- bool(false) + } + ===DONE=== +\ No newline at end of file diff --git a/bug71335.patch b/bug71335.patch new file mode 100644 index 0000000..f258b77 --- /dev/null +++ b/bug71335.patch @@ -0,0 +1,66 @@ +Backported from 5.5 for 5.4 by Remi Collet + +From 285cd3417fb61597345b829f5f573707bbdcd484 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Wed, 13 Jan 2016 16:43:04 -0800 +Subject: [PATCH] Fix bug #71335: Type Confusion in WDDX Packet Deserialization + +--- + ext/wddx/tests/bug71335.phpt | 33 +++++++++++++++++++++++++++++++++ + ext/wddx/wddx.c | 3 ++- + 2 files changed, 35 insertions(+), 1 deletion(-) + create mode 100644 ext/wddx/tests/bug71335.phpt + +diff --git a/ext/wddx/tests/bug71335.phpt b/ext/wddx/tests/bug71335.phpt +new file mode 100644 +index 0000000..57a7f14 +--- /dev/null ++++ b/ext/wddx/tests/bug71335.phpt +@@ -0,0 +1,33 @@ ++--TEST-- ++Bug #71335 (Type Confusion in WDDX Packet Deserialization) ++--SKIPIF-- ++<?php ++if (!extension_loaded("wddx")) print "skip"; ++?> ++--FILE-- ++<?php ++$x = "<?xml version='1.0'?> ++<wddxPacket version='1.0'> ++<header/> ++ <data> ++ <struct> ++ <var name='php_class_name'> ++ <string>stdClass</string> ++ </var> ++ <var name='php_class_name'> ++ <string>stdClass</string> ++ </var> ++ </struct> ++ </data> ++</wddxPacket>"; ++ ++$d = wddx_deserialize($x); ++var_dump($d); ++?> ++DONE ++--EXPECTF-- ++object(stdClass)#%d (1) { ++ ["php_class_name"]=> ++ string(8) "stdClass" ++} ++DONE +diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c +index b9dd1fa..7267ee1 100644 +--- a/ext/wddx/wddx.c ++++ b/ext/wddx/wddx.c +@@ -978,7 +978,8 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name) + + if (ent1->varname) { + if (!strcmp(ent1->varname, PHP_CLASS_NAME_VAR) && +- Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data) && ent2->type == ST_STRUCT) { ++ Z_TYPE_P(ent1->data) == IS_STRING && Z_STRLEN_P(ent1->data) && ++ ent2->type == ST_STRUCT && Z_TYPE_P(ent2->data) == IS_ARRAY) { + zend_bool incomplete_class = 0; + + zend_str_tolower(Z_STRVAL_P(ent1->data), Z_STRLEN_P(ent1->data)); diff --git a/bug71354.patch b/bug71354.patch new file mode 100644 index 0000000..7cbafc5 --- /dev/null +++ b/bug71354.patch @@ -0,0 +1,28 @@ +Backported from 5.5 for 5.4 by Remi Collet +binary patch dropped + +From 13ad4d3e971807f9a58ab5933182907dc2958539 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Wed, 13 Jan 2016 16:32:29 -0800 +Subject: [PATCH] Fix bug #71354 - remove UMR when size is 0 + +--- + ext/phar/phar_object.c | 1 + + ext/phar/tests/bug71354.phpt | 13 +++++++++++++ + ext/phar/tests/bug71354.tar | Bin 0 -> 1536 bytes + 3 files changed, 14 insertions(+) + create mode 100644 ext/phar/tests/bug71354.phpt + create mode 100644 ext/phar/tests/bug71354.tar + +diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c +index 6d25509..e21a982 100644 +--- a/ext/phar/phar_object.c ++++ b/ext/phar/phar_object.c +@@ -4977,6 +4977,7 @@ PHP_METHOD(PharFileInfo, getContent) + + phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC); + Z_TYPE_P(return_value) = IS_STRING; ++ Z_STRVAL_P(return_value) = NULL; + Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0); + + if (!Z_STRVAL_P(return_value)) { diff --git a/bug71391.patch b/bug71391.patch new file mode 100644 index 0000000..538953e --- /dev/null +++ b/bug71391.patch @@ -0,0 +1,31 @@ +Backported from 5.5 for 5.4 by Remi Collet +binary patch dropped + +From 1c1b8b69982375700d4b011eb89ea48b66dbd5aa Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sat, 16 Jan 2016 20:43:43 -0800 +Subject: [PATCH] Fix bug #71391: NULL Pointer Dereference in + phar_tar_setupmetadata() + +--- + ext/phar/tar.c | 3 +++ + ext/phar/tests/bug71391.phpt | 18 ++++++++++++++++++ + ext/phar/tests/bug71391.tar | Bin 0 -> 3584 bytes + 3 files changed, 21 insertions(+) + create mode 100644 ext/phar/tests/bug71391.phpt + create mode 100644 ext/phar/tests/bug71391.tar + +diff --git a/ext/phar/tar.c b/ext/phar/tar.c +index 34ef0ef..5f26805 100644 +--- a/ext/phar/tar.c ++++ b/ext/phar/tar.c +@@ -870,6 +870,9 @@ static int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC) /* {{{ + + if (entry->filename_len >= sizeof(".phar/.metadata") && !memcmp(entry->filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) { + if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 && !memcmp(entry->filename, ".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1)) { ++ if (entry->phar->metadata == NULL) { ++ return ZEND_HASH_APPLY_REMOVE; ++ } + return phar_tar_setmetadata(entry->phar->metadata, entry, error TSRMLS_CC); + } + /* search for the file this metadata entry references */ diff --git a/bug71459.patch b/bug71459.patch new file mode 100644 index 0000000..a028f56 --- /dev/null +++ b/bug71459.patch @@ -0,0 +1,65 @@ +Backported from 5.5 for 5.4 by Remi Collet + +From 54c210d2ea9b8539edcde1888b1104b96b38e886 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Tue, 26 Jan 2016 17:26:52 -0800 +Subject: [PATCH] Fix bug #71459 - Integer overflow in iptcembed() + +--- + ext/standard/iptc.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c +index 05d778b..6f8aa5d 100644 +--- a/ext/standard/iptc.c ++++ b/ext/standard/iptc.c +@@ -195,6 +195,11 @@ PHP_FUNCTION(iptcembed) + RETURN_FALSE; + } + ++ if ((size_t)iptcdata_len >= SIZE_MAX - sizeof(psheader) - 1025) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "IPTC data too large"); ++ RETURN_FALSE; ++ } ++ + if ((fp = VCWD_FOPEN(jpeg_file, "rb")) == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open %s", jpeg_file); + RETURN_FALSE; +@@ -203,7 +208,7 @@ PHP_FUNCTION(iptcembed) + if (spool < 2) { + fstat(fileno(fp), &sb); + +- poi = spoolbuf = safe_emalloc(1, iptcdata_len + sizeof(psheader) + sb.st_size + 1024, 1); ++ poi = spoolbuf = safe_emalloc(1, (size_t)iptcdata_len + sizeof(psheader) + 1024 + 1, sb.st_size); + memset(poi, 0, iptcdata_len + sizeof(psheader) + sb.st_size + 1024 + 1); + } + +From 686a17893a56a500a3a6a4fd721e8ca29412f6dc Mon Sep 17 00:00:00 2001 +From: Anatol Belski <ab@php.net> +Date: Thu, 28 Jan 2016 13:46:34 +0100 +Subject: [PATCH] add missing headers for SIZE_MAX + +--- + ext/standard/iptc.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c +index 6f8aa5d..41a924b 100644 +--- a/ext/standard/iptc.c ++++ b/ext/standard/iptc.c +@@ -38,6 +38,15 @@ + + #include <sys/stat.h> + ++#ifdef PHP_WIN32 ++# include "win32/php_stdint.h" ++#else ++# if HAVE_INTTYPES_H ++# include <inttypes.h> ++# elif HAVE_STDINT_H ++# include <stdint.h> ++# endif ++#endif + + /* some defines for the different JPEG block types */ + #define M_SOF0 0xC0 /* Start Of Frame N */ diff --git a/bug71488.patch b/bug71488.patch new file mode 100644 index 0000000..f4a2609 --- /dev/null +++ b/bug71488.patch @@ -0,0 +1,80 @@ +Backported from 5.5 for 5.4 by Remi Collet +binary patch dropped + +From 07c7df68bd68bbe706371fccc77c814ebb335d9e Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 31 Jan 2016 19:37:56 -0800 +Subject: [PATCH] Fixed bug #71488: Stack overflow when decompressing tar + archives + +--- + ext/phar/tar.c | 22 ++++++++++++++++------ + ext/phar/tests/bug71488.phpt | 16 ++++++++++++++++ + ext/phar/tests/bug71488.tar | Bin 0 -> 10240 bytes + 3 files changed, 32 insertions(+), 6 deletions(-) + create mode 100644 ext/phar/tests/bug71488.phpt + create mode 100644 ext/phar/tests/bug71488.tar + +diff --git a/ext/phar/tar.c b/ext/phar/tar.c +index 5f26805..3a4bd49 100644 +--- a/ext/phar/tar.c ++++ b/ext/phar/tar.c +@@ -192,6 +192,13 @@ static int phar_tar_process_metadata(pha + } + /* }}} */ + ++#if !HAVE_STRNLEN ++static size_t strnlen(const char *s, size_t maxlen) { ++ char *r = (char *)memchr(s, '\0', maxlen); ++ return r ? r-s : maxlen; ++} ++#endif ++ + int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, int is_data, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */ + { + char buf[512], *actual_alias = NULL, *p; +@@ -201,6 +208,7 @@ int phar_parse_tarfile(php_stream* fp, c + php_uint32 sum1, sum2, size, old; + phar_archive_data *myphar, **actual; + int last_was_longlink = 0; ++ int linkname_len; + + if (error) { + *error = NULL; +@@ -255,7 +263,7 @@ int phar_parse_tarfile(php_stream* fp, c + size = entry.uncompressed_filesize = entry.compressed_filesize = + phar_tar_number(hdr->size, sizeof(hdr->size)); + +- if (((!old && hdr->prefix[0] == 0) || old) && strlen(hdr->name) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { ++ if (((!old && hdr->prefix[0] == 0) || old) && strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { + off_t curloc; + + if (size > 511) { +@@ -465,20 +473,22 @@ bail: + } + + entry.link = NULL; +- ++ /* link field is null-terminated unless it has 100 non-null chars. ++ * Thus we can not use strlen. */ ++ linkname_len = strnlen(hdr->linkname, 100); + if (entry.tar_type == TAR_LINK) { +- if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) { ++ if (!zend_hash_exists(&myphar->manifest, hdr->linkname, linkname_len)) { + if (error) { +- spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname); ++ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%.*s\"", fname, linkname_len, hdr->linkname); + } + pefree(entry.filename, entry.is_persistent); + php_stream_close(fp); + phar_destroy_phar_data(myphar TSRMLS_CC); + return FAILURE; + } +- entry.link = estrdup(hdr->linkname); ++ entry.link = estrndup(hdr->linkname, linkname_len); + } else if (entry.tar_type == TAR_SYMLINK) { +- entry.link = estrdup(hdr->linkname); ++ entry.link = estrndup(hdr->linkname, linkname_len); + } + phar_set_inode(&entry TSRMLS_CC); + zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry); @@ -1,4 +1,4 @@ -===== 5.5.45-3 (2016-01-06) +===== 5.5.45-4 (2016-02-16) $ grep -r 'Tests failed' /var/lib/mock/*/build.log diff --git a/pcre838.patch b/pcre838.patch new file mode 100644 index 0000000..3b3dcdf --- /dev/null +++ b/pcre838.patch @@ -0,0 +1,6665 @@ +Backported from 5.5 for 5.4 by Remi Collet + + +diff -ru php-5.4.45/ext/pcre/pcrelib/config.h php55/php-5.5.31/ext/pcre/pcrelib/config.h +--- php-5.4.45/ext/pcre/pcrelib/config.h 2015-09-01 22:09:37.000000000 +0200 ++++ php-5.5.31/ext/pcre/pcrelib/config.h 2016-01-06 10:36:49.000000000 +0100 +@@ -302,6 +302,8 @@ + */ + /* #undef NO_RECURSE */ + ++#define PARENS_NEST_LIMIT 250 ++ + /* Name of package */ + #define PACKAGE "pcre" + +diff -ru php54/php-5.4.45/ext/pcre/pcrelib/pcre_exec.c php55/php-5.5.31/ext/pcre/pcrelib/pcre_exec.c +--- php-5.4.45/ext/pcre/pcrelib/pcre_exec.c 2015-09-01 22:09:37.000000000 +0200 ++++ php-5.5.31/ext/pcre/pcrelib/pcre_exec.c 2016-01-06 10:36:49.000000000 +0100 +@@ -688,7 +688,7 @@ + #define foc number + #define save_mark data + +-/* These statements are here to stop the compiler complaining about unitialized ++/* These statements are here to stop the compiler complaining about uninitialized + variables. */ + + #ifdef SUPPORT_UCP + +From ca02d9c2d6f9bea7bf8abe607f1ee9484b1d7b62 Mon Sep 17 00:00:00 2001 +From: Stanislav Malyshev <stas@php.net> +Date: Sun, 31 Jan 2016 20:33:17 -0800 +Subject: [PATCH] Upgrade bundled PCRE to 8.38 + +--- + NEWS | 3 + + ext/pcre/pcrelib/ChangeLog | 176 ++ + ext/pcre/pcrelib/NEWS | 8 + + ext/pcre/pcrelib/config.h | 11 +- + ext/pcre/pcrelib/doc/pcre.txt | 2130 +++++++++++----------- + ext/pcre/pcrelib/pcre.h | 4 +- + ext/pcre/pcrelib/pcre_compile.c | 334 +++- + ext/pcre/pcrelib/pcre_exec.c | 5 +- + ext/pcre/pcrelib/pcre_internal.h | 17 +- + ext/pcre/pcrelib/pcre_jit_compile.c | 77 +- + ext/pcre/pcrelib/pcre_study.c | 19 +- + ext/pcre/pcrelib/pcre_xclass.c | 2 +- + ext/pcre/pcrelib/sljit/sljitConfig.h | 9 + + ext/pcre/pcrelib/sljit/sljitConfigInternal.h | 13 +- + ext/pcre/pcrelib/sljit/sljitLir.c | 10 +- + ext/pcre/pcrelib/sljit/sljitLir.h | 128 +- + ext/pcre/pcrelib/sljit/sljitNativeARM_32.c | 27 +- + ext/pcre/pcrelib/sljit/sljitNativeARM_64.c | 48 +- + ext/pcre/pcrelib/sljit/sljitNativeARM_T2_32.c | 58 +- + ext/pcre/pcrelib/sljit/sljitNativeMIPS_common.c | 15 +- + ext/pcre/pcrelib/sljit/sljitNativePPC_common.c | 23 +- + ext/pcre/pcrelib/sljit/sljitNativeSPARC_common.c | 19 +- + ext/pcre/pcrelib/sljit/sljitNativeTILEGX_64.c | 311 ++-- + ext/pcre/pcrelib/sljit/sljitNativeX86_common.c | 129 +- + ext/pcre/pcrelib/testdata/grepoutput | 12 + + ext/pcre/pcrelib/testdata/testinput1 | 13 + + ext/pcre/pcrelib/testdata/testinput11 | 4 + + ext/pcre/pcrelib/testdata/testinput12 | 17 + + ext/pcre/pcrelib/testdata/testinput14 | 2 + + ext/pcre/pcrelib/testdata/testinput17 | 2 + + ext/pcre/pcrelib/testdata/testinput2 | 139 ++ + ext/pcre/pcrelib/testdata/testinput4 | 5 + + ext/pcre/pcrelib/testdata/testinput5 | 8 + + ext/pcre/pcrelib/testdata/testinput6 | 57 + + ext/pcre/pcrelib/testdata/testinput7 | 15 + + ext/pcre/pcrelib/testdata/testinput8 | 4 + + ext/pcre/pcrelib/testdata/testinputEBC | 3 + + ext/pcre/pcrelib/testdata/testoutput1 | 23 + + ext/pcre/pcrelib/testdata/testoutput11-16 | 50 +- + ext/pcre/pcrelib/testdata/testoutput11-32 | 50 +- + ext/pcre/pcrelib/testdata/testoutput11-8 | 50 +- + ext/pcre/pcrelib/testdata/testoutput12 | 25 + + ext/pcre/pcrelib/testdata/testoutput14 | 2 + + ext/pcre/pcrelib/testdata/testoutput17 | 2 + + ext/pcre/pcrelib/testdata/testoutput2 | 380 +++- + ext/pcre/pcrelib/testdata/testoutput4 | 6 + + ext/pcre/pcrelib/testdata/testoutput5 | 45 + + ext/pcre/pcrelib/testdata/testoutput6 | 96 + + ext/pcre/pcrelib/testdata/testoutput7 | 57 +- + ext/pcre/pcrelib/testdata/testoutput8 | 6 + + ext/pcre/pcrelib/testdata/testoutputEBC | 6 + + 51 files changed, 3144 insertions(+), 1511 deletions(-) + +diff --git a/ext/pcre/pcrelib/ChangeLog b/ext/pcre/pcrelib/ChangeLog +index 359b412..5e5bf18 100644 +--- a/ext/pcre/pcrelib/ChangeLog ++++ b/ext/pcre/pcrelib/ChangeLog +@@ -1,6 +1,182 @@ + ChangeLog for PCRE + ------------------ + ++Note that the PCRE 8.xx series (PCRE1) is now in a bugfix-only state. All ++development is happening in the PCRE2 10.xx series. ++ ++Version 8.38 23-November-2015 ++----------------------------- ++ ++1. If a group that contained a recursive back reference also contained a ++ forward reference subroutine call followed by a non-forward-reference ++ subroutine call, for example /.((?2)(?R)\1)()/, pcre2_compile() failed to ++ compile correct code, leading to undefined behaviour or an internally ++ detected error. This bug was discovered by the LLVM fuzzer. ++ ++2. Quantification of certain items (e.g. atomic back references) could cause ++ incorrect code to be compiled when recursive forward references were ++ involved. For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/. ++ This bug was discovered by the LLVM fuzzer. ++ ++3. A repeated conditional group whose condition was a reference by name caused ++ a buffer overflow if there was more than one group with the given name. ++ This bug was discovered by the LLVM fuzzer. ++ ++4. A recursive back reference by name within a group that had the same name as ++ another group caused a buffer overflow. For example: ++ /(?J)(?'d'(?'d'\g{d}))/. This bug was discovered by the LLVM fuzzer. ++ ++5. A forward reference by name to a group whose number is the same as the ++ current group, for example in this pattern: /(?|(\k'Pm')|(?'Pm'))/, caused ++ a buffer overflow at compile time. This bug was discovered by the LLVM ++ fuzzer. ++ ++6. A lookbehind assertion within a set of mutually recursive subpatterns could ++ provoke a buffer overflow. This bug was discovered by the LLVM fuzzer. ++ ++7. Another buffer overflow bug involved duplicate named groups with a ++ reference between their definition, with a group that reset capture ++ numbers, for example: /(?J:(?|(?'R')(\k'R')|((?'R'))))/. This has been ++ fixed by always allowing for more memory, even if not needed. (A proper fix ++ is implemented in PCRE2, but it involves more refactoring.) ++ ++8. There was no check for integer overflow in subroutine calls such as (?123). ++ ++9. The table entry for \l in EBCDIC environments was incorrect, leading to its ++ being treated as a literal 'l' instead of causing an error. ++ ++10. There was a buffer overflow if pcre_exec() was called with an ovector of ++ size 1. This bug was found by american fuzzy lop. ++ ++11. If a non-capturing group containing a conditional group that could match ++ an empty string was repeated, it was not identified as matching an empty ++ string itself. For example: /^(?:(?(1)x|)+)+$()/. ++ ++12. In an EBCDIC environment, pcretest was mishandling the escape sequences ++ \a and \e in test subject lines. ++ ++13. In an EBCDIC environment, \a in a pattern was converted to the ASCII ++ instead of the EBCDIC value. ++ ++14. The handling of \c in an EBCDIC environment has been revised so that it is ++ now compatible with the specification in Perl's perlebcdic page. ++ ++15. The EBCDIC character 0x41 is a non-breaking space, equivalent to 0xa0 in ++ ASCII/Unicode. This has now been added to the list of characters that are ++ recognized as white space in EBCDIC. ++ ++16. When PCRE was compiled without UCP support, the use of \p and \P gave an ++ error (correctly) when used outside a class, but did not give an error ++ within a class. ++ ++17. \h within a class was incorrectly compiled in EBCDIC environments. ++ ++18. A pattern with an unmatched closing parenthesis that contained a backward ++ assertion which itself contained a forward reference caused buffer ++ overflow. And example pattern is: /(?=di(?<=(?1))|(?=(.))))/. ++ ++19. JIT should return with error when the compiled pattern requires more stack ++ space than the maximum. ++ ++20. A possessively repeated conditional group that could match an empty string, ++ for example, /(?(R))*+/, was incorrectly compiled. ++ ++21. Fix infinite recursion in the JIT compiler when certain patterns such as ++ /(?:|a|){100}x/ are analysed. ++ ++22. Some patterns with character classes involving [: and \\ were incorrectly ++ compiled and could cause reading from uninitialized memory or an incorrect ++ error diagnosis. ++ ++23. Pathological patterns containing many nested occurrences of [: caused ++ pcre_compile() to run for a very long time. ++ ++24. A conditional group with only one branch has an implicit empty alternative ++ branch and must therefore be treated as potentially matching an empty ++ string. ++ ++25. If (?R was followed by - or + incorrect behaviour happened instead of a ++ diagnostic. ++ ++26. Arrange to give up on finding the minimum matching length for overly ++ complex patterns. ++ ++27. Similar to (4) above: in a pattern with duplicated named groups and an ++ occurrence of (?| it is possible for an apparently non-recursive back ++ reference to become recursive if a later named group with the relevant ++ number is encountered. This could lead to a buffer overflow. Wen Guanxing ++ from Venustech ADLAB discovered this bug. ++ ++28. If pcregrep was given the -q option with -c or -l, or when handling a ++ binary file, it incorrectly wrote output to stdout. ++ ++29. The JIT compiler did not restore the control verb head in case of *THEN ++ control verbs. This issue was found by Karl Skomski with a custom LLVM ++ fuzzer. ++ ++30. Error messages for syntax errors following \g and \k were giving inaccurate ++ offsets in the pattern. ++ ++31. Added a check for integer overflow in conditions (?(<digits>) and ++ (?(R<digits>). This omission was discovered by Karl Skomski with the LLVM ++ fuzzer. ++ ++32. Handling recursive references such as (?2) when the reference is to a group ++ later in the pattern uses code that is very hacked about and error-prone. ++ It has been re-written for PCRE2. Here in PCRE1, a check has been added to ++ give an internal error if it is obvious that compiling has gone wrong. ++ ++33. The JIT compiler should not check repeats after a {0,1} repeat byte code. ++ This issue was found by Karl Skomski with a custom LLVM fuzzer. ++ ++34. The JIT compiler should restore the control chain for empty possessive ++ repeats. This issue was found by Karl Skomski with a custom LLVM fuzzer. ++ ++35. Match limit check added to JIT recursion. This issue was found by Karl ++ Skomski with a custom LLVM fuzzer. ++ ++36. Yet another case similar to 27 above has been circumvented by an ++ unconditional allocation of extra memory. This issue is fixed "properly" in ++ PCRE2 by refactoring the way references are handled. Wen Guanxing ++ from Venustech ADLAB discovered this bug. ++ ++37. Fix two assertion fails in JIT. These issues were found by Karl Skomski ++ with a custom LLVM fuzzer. ++ ++38. Fixed a corner case of range optimization in JIT. ++ ++39. An incorrect error "overran compiling workspace" was given if there were ++ exactly enough group forward references such that the last one extended ++ into the workspace safety margin. The next one would have expanded the ++ workspace. The test for overflow was not including the safety margin. ++ ++40. A match limit issue is fixed in JIT which was found by Karl Skomski ++ with a custom LLVM fuzzer. ++ ++41. Remove the use of /dev/null in testdata/testinput2, because it doesn't ++ work under Windows. (Why has it taken so long for anyone to notice?) ++ ++42. In a character class such as [\W\p{Any}] where both a negative-type escape ++ ("not a word character") and a property escape were present, the property ++ escape was being ignored. ++ ++43. Fix crash caused by very long (*MARK) or (*THEN) names. ++ ++44. A sequence such as [[:punct:]b] that is, a POSIX character class followed ++ by a single ASCII character in a class item, was incorrectly compiled in ++ UCP mode. The POSIX class got lost, but only if the single character ++ followed it. ++ ++45. [:punct:] in UCP mode was matching some characters in the range 128-255 ++ that should not have been matched. ++ ++46. If [:^ascii:] or [:^xdigit:] or [:^cntrl:] are present in a non-negated ++ class, all characters with code points greater than 255 are in the class. ++ When a Unicode property was also in the class (if PCRE_UCP is set, escapes ++ such as \w are turned into Unicode properties), wide characters were not ++ correctly handled, and could fail to match. ++ ++ + Version 8.37 28-April-2015 + -------------------------- + +diff --git a/ext/pcre/pcrelib/NEWS b/ext/pcre/pcrelib/NEWS +index 064bf27..7e42dcb 100644 +--- a/ext/pcre/pcrelib/NEWS ++++ b/ext/pcre/pcrelib/NEWS +@@ -1,6 +1,14 @@ + News about PCRE releases + ------------------------ + ++Release 8.38 23-November-2015 ++----------------------------- ++ ++This is bug-fix release. Note that this library (now called PCRE1) is now being ++maintained for bug fixes only. New projects are advised to use the new PCRE2 ++libraries. ++ ++ + Release 8.37 28-April-2015 + -------------------------- + +diff --git a/ext/pcre/pcrelib/config.h b/ext/pcre/pcrelib/config.h +index ba06a17..0f7a9f7 100644 +--- a/ext/pcre/pcrelib/config.h ++++ b/ext/pcre/pcrelib/config.h +@@ -234,8 +234,8 @@ them both to 0; an emulation function will be used. */ + #define LINK_SIZE 2 + #endif + +-/* Define to the sub-directory in which libtool stores uninstalled libraries. +- */ ++/* 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 +@@ -314,7 +314,7 @@ them both to 0; an emulation function will be used. */ + #define PACKAGE_NAME "PCRE" + + /* Define to the full name and version of this package. */ +-#define PACKAGE_STRING "PCRE 8.37" ++#define PACKAGE_STRING "PCRE 8.38" + + /* Define to the one symbol short name of this package. */ + #define PACKAGE_TARNAME "pcre" +@@ -323,7 +323,7 @@ them both to 0; an emulation function will be used. */ + #define PACKAGE_URL "" + + /* Define to the version of this package. */ +-#define PACKAGE_VERSION "8.37" ++#define PACKAGE_VERSION "8.38" + + /* to make a symbol visible */ + /* #undef PCRECPP_EXP_DECL */ +@@ -439,7 +439,7 @@ them both to 0; an emulation function will be used. */ + + /* Version number of package */ + #ifndef VERSION +-#define VERSION "8.37" ++#define VERSION "8.38" + #endif + + /* Define to empty if `const' does not conform to ANSI C. */ +@@ -451,4 +451,3 @@ them both to 0; an emulation function will be used. */ + + /* Define to `unsigned int' if <sys/types.h> does not define. */ + /* #undef size_t */ +- +diff --git a/ext/pcre/pcrelib/doc/pcre.txt b/ext/pcre/pcrelib/doc/pcre.txt +index ce27f4b..76a47c7 100644 +--- a/ext/pcre/pcrelib/doc/pcre.txt ++++ b/ext/pcre/pcrelib/doc/pcre.txt +@@ -13,7 +13,18 @@ PCRE(3) Library Functions Manual PCRE(3) + + + NAME +- PCRE - Perl-compatible regular expressions ++ PCRE - Perl-compatible regular expressions (original API) ++ ++PLEASE TAKE NOTE ++ ++ This document relates to PCRE releases that use the original API, with ++ library names libpcre, libpcre16, and libpcre32. January 2015 saw the ++ first release of a new API, known as PCRE2, with release numbers start- ++ ing at 10.00 and library names libpcre2-8, libpcre2-16, and ++ libpcre2-32. The old libraries (now called PCRE1) are still being main- ++ tained for bug fixes, but there will be no new development. New ++ projects are advised to use the new PCRE2 libraries. ++ + + INTRODUCTION + +@@ -179,8 +190,8 @@ AUTHOR + + REVISION + +- Last updated: 08 January 2014 +- Copyright (c) 1997-2014 University of Cambridge. ++ Last updated: 10 February 2015 ++ Copyright (c) 1997-2015 University of Cambridge. + ------------------------------------------------------------------------------ + + +@@ -4989,7 +5000,8 @@ BACKSLASH + appearance of non-printing characters, apart from the binary zero that + terminates a pattern, but when a pattern is being prepared by text + editing, it is often easier to use one of the following escape +- sequences than the binary character it represents: ++ sequences than the binary character it represents. In an ASCII or Uni- ++ code environment, these escapes are as follows: + + \a alarm, that is, the BEL character (hex 07) + \cx "control-x", where x is any ASCII character +@@ -5005,55 +5017,67 @@ BACKSLASH + \x{hhh..} character with hex code hhh.. (non-JavaScript mode) + \uhhhh character with hex code hhhh (JavaScript mode only) + +- The precise effect of \cx on ASCII characters is as follows: if x is a +- lower case letter, it is converted to upper case. Then bit 6 of the ++ The precise effect of \cx on ASCII characters is as follows: if x is a ++ lower case letter, it is converted to upper case. Then bit 6 of the + character (hex 40) is inverted. Thus \cA to \cZ become hex 01 to hex 1A +- (A is 41, Z is 5A), but \c{ becomes hex 3B ({ is 7B), and \c; becomes +- hex 7B (; is 3B). If the data item (byte or 16-bit value) following \c +- has a value greater than 127, a compile-time error occurs. This locks ++ (A is 41, Z is 5A), but \c{ becomes hex 3B ({ is 7B), and \c; becomes ++ hex 7B (; is 3B). If the data item (byte or 16-bit value) following \c ++ has a value greater than 127, a compile-time error occurs. This locks + out non-ASCII characters in all modes. + +- The \c facility was designed for use with ASCII characters, but with +- the extension to Unicode it is even less useful than it once was. It +- is, however, recognized when PCRE is compiled in EBCDIC mode, where +- data items are always bytes. In this mode, all values are valid after +- \c. If the next character is a lower case letter, it is converted to +- upper case. Then the 0xc0 bits of the byte are inverted. Thus \cA +- becomes hex 01, as in ASCII (A is C1), but because the EBCDIC letters +- are disjoint, \cZ becomes hex 29 (Z is E9), and other characters also +- generate different values. +- +- After \0 up to two further octal digits are read. If there are fewer +- than two digits, just those that are present are used. Thus the +- sequence \0\x\07 specifies two binary zeros followed by a BEL character +- (code value 7). Make sure you supply two digits after the initial zero ++ When PCRE is compiled in EBCDIC mode, \a, \e, \f, \n, \r, and \t gener- ++ ate the appropriate EBCDIC code values. The \c escape is processed as ++ specified for Perl in the perlebcdic document. The only characters that ++ are allowed after \c are A-Z, a-z, or one of @, [, \, ], ^, _, or ?. ++ Any other character provokes a compile-time error. The sequence \@ ++ encodes character code 0; the letters (in either case) encode charac- ++ ters 1-26 (hex 01 to hex 1A); [, \, ], ^, and _ encode characters 27-31 ++ (hex 1B to hex 1F), and \? becomes either 255 (hex FF) or 95 (hex 5F). ++ ++ Thus, apart from \?, these escapes generate the same character code ++ values as they do in an ASCII environment, though the meanings of the ++ values mostly differ. For example, \G always generates code value 7, ++ which is BEL in ASCII but DEL in EBCDIC. ++ ++ The sequence \? generates DEL (127, hex 7F) in an ASCII environment, ++ but because 127 is not a control character in EBCDIC, Perl makes it ++ generate the APC character. Unfortunately, there are several variants ++ of EBCDIC. In most of them the APC character has the value 255 (hex ++ FF), but in the one Perl calls POSIX-BC its value is 95 (hex 5F). If ++ certain other characters have POSIX-BC values, PCRE makes \? generate ++ 95; otherwise it generates 255. ++ ++ After \0 up to two further octal digits are read. If there are fewer ++ than two digits, just those that are present are used. Thus the ++ sequence \0\x\015 specifies two binary zeros followed by a CR character ++ (code value 13). Make sure you supply two digits after the initial zero + if the pattern character that follows is itself an octal digit. + +- The escape \o must be followed by a sequence of octal digits, enclosed +- in braces. An error occurs if this is not the case. This escape is a +- recent addition to Perl; it provides way of specifying character code +- points as octal numbers greater than 0777, and it also allows octal ++ The escape \o must be followed by a sequence of octal digits, enclosed ++ in braces. An error occurs if this is not the case. This escape is a ++ recent addition to Perl; it provides way of specifying character code ++ points as octal numbers greater than 0777, and it also allows octal + numbers and back references to be unambiguously specified. + + For greater clarity and unambiguity, it is best to avoid following \ by + a digit greater than zero. Instead, use \o{} or \x{} to specify charac- +- ter numbers, and \g{} to specify back references. The following para- ++ ter numbers, and \g{} to specify back references. The following para- + graphs describe the old, ambiguous syntax. + + The handling of a backslash followed by a digit other than 0 is compli- +- cated, and Perl has changed in recent releases, causing PCRE also to ++ cated, and Perl has changed in recent releases, causing PCRE also to + change. Outside a character class, PCRE reads the digit and any follow- +- ing digits as a decimal number. If the number is less than 8, or if +- there have been at least that many previous capturing left parentheses +- in the expression, the entire sequence is taken as a back reference. A +- description of how this works is given later, following the discussion ++ ing digits as a decimal number. If the number is less than 8, or if ++ there have been at least that many previous capturing left parentheses ++ in the expression, the entire sequence is taken as a back reference. A ++ description of how this works is given later, following the discussion + of parenthesized subpatterns. + +- Inside a character class, or if the decimal number following \ is ++ Inside a character class, or if the decimal number following \ is + greater than 7 and there have not been that many capturing subpatterns, +- PCRE handles \8 and \9 as the literal characters "8" and "9", and oth- ++ PCRE handles \8 and \9 as the literal characters "8" and "9", and oth- + erwise re-reads up to three octal digits following the backslash, using +- them to generate a data character. Any subsequent digits stand for ++ them to generate a data character. Any subsequent digits stand for + themselves. For example: + + \040 is another way of writing an ASCII space +@@ -5071,31 +5095,31 @@ BACKSLASH + \81 is either a back reference, or the two + characters "8" and "1" + +- Note that octal values of 100 or greater that are specified using this +- syntax must not be introduced by a leading zero, because no more than ++ Note that octal values of 100 or greater that are specified using this ++ syntax must not be introduced by a leading zero, because no more than + three octal digits are ever read. + +- By default, after \x that is not followed by {, from zero to two hexa- +- decimal digits are read (letters can be in upper or lower case). Any ++ By default, after \x that is not followed by {, from zero to two hexa- ++ decimal digits are read (letters can be in upper or lower case). Any + number of hexadecimal digits may appear between \x{ and }. If a charac- +- ter other than a hexadecimal digit appears between \x{ and }, or if ++ ter other than a hexadecimal digit appears between \x{ and }, or if + there is no terminating }, an error occurs. + +- If the PCRE_JAVASCRIPT_COMPAT option is set, the interpretation of \x +- is as just described only when it is followed by two hexadecimal dig- +- its. Otherwise, it matches a literal "x" character. In JavaScript ++ If the PCRE_JAVASCRIPT_COMPAT option is set, the interpretation of \x ++ is as just described only when it is followed by two hexadecimal dig- ++ its. Otherwise, it matches a literal "x" character. In JavaScript + mode, support for code points greater than 256 is provided by \u, which +- must be followed by four hexadecimal digits; otherwise it matches a ++ must be followed by four hexadecimal digits; otherwise it matches a + literal "u" character. + + Characters whose value is less than 256 can be defined by either of the +- two syntaxes for \x (or by \u in JavaScript mode). There is no differ- ++ two syntaxes for \x (or by \u in JavaScript mode). There is no differ- + ence in the way they are handled. For example, \xdc is exactly the same + as \x{dc} (or \u00dc in JavaScript mode). + + Constraints on character values + +- Characters that are specified using octal or hexadecimal numbers are ++ Characters that are specified using octal or hexadecimal numbers are + limited to certain values, as follows: + + 8-bit non-UTF mode less than 0x100 +@@ -5105,44 +5129,44 @@ BACKSLASH + 32-bit non-UTF mode less than 0x100000000 + 32-bit UTF-32 mode less than 0x10ffff and a valid codepoint + +- Invalid Unicode codepoints are the range 0xd800 to 0xdfff (the so- ++ Invalid Unicode codepoints are the range 0xd800 to 0xdfff (the so- + called "surrogate" codepoints), and 0xffef. + + Escape sequences in character classes + + All the sequences that define a single character value can be used both +- inside and outside character classes. In addition, inside a character ++ inside and outside character classes. In addition, inside a character + class, \b is interpreted as the backspace character (hex 08). + +- \N is not allowed in a character class. \B, \R, and \X are not special +- inside a character class. Like other unrecognized escape sequences, +- they are treated as the literal characters "B", "R", and "X" by +- default, but cause an error if the PCRE_EXTRA option is set. Outside a ++ \N is not allowed in a character class. \B, \R, and \X are not special ++ inside a character class. Like other unrecognized escape sequences, ++ they are treated as the literal characters "B", "R", and "X" by ++ default, but cause an error if the PCRE_EXTRA option is set. Outside a + character class, these sequences have different meanings. + + Unsupported escape sequences + +- In Perl, the sequences \l, \L, \u, and \U are recognized by its string +- handler and used to modify the case of following characters. By +- default, PCRE does not support these escape sequences. However, if the +- PCRE_JAVASCRIPT_COMPAT option is set, \U matches a "U" character, and ++ In Perl, the sequences \l, \L, \u, and \U are recognized by its string ++ handler and used to modify the case of following characters. By ++ default, PCRE does not support these escape sequences. However, if the ++ PCRE_JAVASCRIPT_COMPAT option is set, \U matches a "U" character, and + \u can be used to define a character by code point, as described in the + previous section. + + Absolute and relative back references + +- The sequence \g followed by an unsigned or a negative number, option- +- ally enclosed in braces, is an absolute or relative back reference. A ++ The sequence \g followed by an unsigned or a negative number, option- ++ ally enclosed in braces, is an absolute or relative back reference. A + named back reference can be coded as \g{name}. Back references are dis- + cussed later, following the discussion of parenthesized subpatterns. + + Absolute and relative subroutine calls + +- For compatibility with Oniguruma, the non-Perl syntax \g followed by a ++ For compatibility with Oniguruma, the non-Perl syntax \g followed by a + name or a number enclosed either in angle brackets or single quotes, is +- an alternative syntax for referencing a subpattern as a "subroutine". +- Details are discussed later. Note that \g{...} (Perl syntax) and +- \g<...> (Oniguruma syntax) are not synonymous. The former is a back ++ an alternative syntax for referencing a subpattern as a "subroutine". ++ Details are discussed later. Note that \g{...} (Perl syntax) and ++ \g<...> (Oniguruma syntax) are not synonymous. The former is a back + reference; the latter is a subroutine call. + + Generic character types +@@ -5161,59 +5185,59 @@ BACKSLASH + \W any "non-word" character + + There is also the single sequence \N, which matches a non-newline char- +- acter. This is the same as the "." metacharacter when PCRE_DOTALL is +- not set. Perl also uses \N to match characters by name; PCRE does not ++ acter. This is the same as the "." metacharacter when PCRE_DOTALL is ++ not set. Perl also uses \N to match characters by name; PCRE does not + support this. + +- Each pair of lower and upper case escape sequences partitions the com- +- plete set of characters into two disjoint sets. Any given character +- matches one, and only one, of each pair. The sequences can appear both +- inside and outside character classes. They each match one character of +- the appropriate type. If the current matching point is at the end of +- the subject string, all of them fail, because there is no character to ++ Each pair of lower and upper case escape sequences partitions the com- ++ plete set of characters into two disjoint sets. Any given character ++ matches one, and only one, of each pair. The sequences can appear both ++ inside and outside character classes. They each match one character of ++ the appropriate type. If the current matching point is at the end of ++ the subject string, all of them fail, because there is no character to + match. + +- For compatibility with Perl, \s did not used to match the VT character +- (code 11), which made it different from the the POSIX "space" class. +- However, Perl added VT at release 5.18, and PCRE followed suit at +- release 8.34. The default \s characters are now HT (9), LF (10), VT +- (11), FF (12), CR (13), and space (32), which are defined as white ++ For compatibility with Perl, \s did not used to match the VT character ++ (code 11), which made it different from the the POSIX "space" class. ++ However, Perl added VT at release 5.18, and PCRE followed suit at ++ release 8.34. The default \s characters are now HT (9), LF (10), VT ++ (11), FF (12), CR (13), and space (32), which are defined as white + space in the "C" locale. This list may vary if locale-specific matching +- is taking place. For example, in some locales the "non-breaking space" +- character (\xA0) is recognized as white space, and in others the VT ++ is taking place. For example, in some locales the "non-breaking space" ++ character (\xA0) is recognized as white space, and in others the VT + character is not. + +- A "word" character is an underscore or any character that is a letter +- or digit. By default, the definition of letters and digits is con- +- trolled by PCRE's low-valued character tables, and may vary if locale- +- specific matching is taking place (see "Locale support" in the pcreapi +- page). For example, in a French locale such as "fr_FR" in Unix-like +- systems, or "french" in Windows, some character codes greater than 127 +- are used for accented letters, and these are then matched by \w. The ++ A "word" character is an underscore or any character that is a letter ++ or digit. By default, the definition of letters and digits is con- ++ trolled by PCRE's low-valued character tables, and may vary if locale- ++ specific matching is taking place (see "Locale support" in the pcreapi ++ page). For example, in a French locale such as "fr_FR" in Unix-like ++ systems, or "french" in Windows, some character codes greater than 127 ++ are used for accented letters, and these are then matched by \w. The + use of locales with Unicode is discouraged. + +- By default, characters whose code points are greater than 127 never ++ By default, characters whose code points are greater than 127 never + match \d, \s, or \w, and always match \D, \S, and \W, although this may +- vary for characters in the range 128-255 when locale-specific matching +- is happening. These escape sequences retain their original meanings +- from before Unicode support was available, mainly for efficiency rea- +- sons. If PCRE is compiled with Unicode property support, and the +- PCRE_UCP option is set, the behaviour is changed so that Unicode prop- ++ vary for characters in the range 128-255 when locale-specific matching ++ is happening. These escape sequences retain their original meanings ++ from before Unicode support was available, mainly for efficiency rea- ++ sons. If PCRE is compiled with Unicode property support, and the ++ PCRE_UCP option is set, the behaviour is changed so that Unicode prop- + erties are used to determine character types, as follows: + + \d any character that matches \p{Nd} (decimal digit) + \s any character that matches \p{Z} or \h or \v + \w any character that matches \p{L} or \p{N}, plus underscore + +- The upper case escapes match the inverse sets of characters. Note that +- \d matches only decimal digits, whereas \w matches any Unicode digit, +- as well as any Unicode letter, and underscore. Note also that PCRE_UCP +- affects \b, and \B because they are defined in terms of \w and \W. ++ The upper case escapes match the inverse sets of characters. Note that ++ \d matches only decimal digits, whereas \w matches any Unicode digit, ++ as well as any Unicode letter, and underscore. Note also that PCRE_UCP ++ affects \b, and \B because they are defined in terms of \w and \W. + Matching these sequences is noticeably slower when PCRE_UCP is set. + +- The sequences \h, \H, \v, and \V are features that were added to Perl +- at release 5.10. In contrast to the other sequences, which match only +- ASCII characters by default, these always match certain high-valued ++ The sequences \h, \H, \v, and \V are features that were added to Perl ++ at release 5.10. In contrast to the other sequences, which match only ++ ASCII characters by default, these always match certain high-valued + code points, whether or not PCRE_UCP is set. The horizontal space char- + acters are: + +@@ -5252,110 +5276,110 @@ BACKSLASH + + Newline sequences + +- Outside a character class, by default, the escape sequence \R matches +- any Unicode newline sequence. In 8-bit non-UTF-8 mode \R is equivalent ++ Outside a character class, by default, the escape sequence \R matches ++ any Unicode newline sequence. In 8-bit non-UTF-8 mode \R is equivalent + to the following: + + (?>\r\n|\n|\x0b|\f|\r|\x85) + +- This is an example of an "atomic group", details of which are given ++ This is an example of an "atomic group", details of which are given + below. This particular group matches either the two-character sequence +- CR followed by LF, or one of the single characters LF (linefeed, +- U+000A), VT (vertical tab, U+000B), FF (form feed, U+000C), CR (car- +- riage return, U+000D), or NEL (next line, U+0085). The two-character ++ CR followed by LF, or one of the single characters LF (linefeed, ++ U+000A), VT (vertical tab, U+000B), FF (form feed, U+000C), CR (car- ++ riage return, U+000D), or NEL (next line, U+0085). The two-character + sequence is treated as a single unit that cannot be split. + +- In other modes, two additional characters whose codepoints are greater ++ In other modes, two additional characters whose codepoints are greater + than 255 are added: LS (line separator, U+2028) and PS (paragraph sepa- +- rator, U+2029). Unicode character property support is not needed for ++ rator, U+2029). Unicode character property support is not needed for + these characters to be recognized. + + It is possible to restrict \R to match only CR, LF, or CRLF (instead of +- the complete set of Unicode line endings) by setting the option ++ the complete set of Unicode line endings) by setting the option + PCRE_BSR_ANYCRLF either at compile time or when the pattern is matched. + (BSR is an abbrevation for "backslash R".) This can be made the default +- when PCRE is built; if this is the case, the other behaviour can be +- requested via the PCRE_BSR_UNICODE option. It is also possible to +- specify these settings by starting a pattern string with one of the ++ when PCRE is built; if this is the case, the other behaviour can be ++ requested via the PCRE_BSR_UNICODE option. It is also possible to ++ specify these settings by starting a pattern string with one of the + following sequences: + + (*BSR_ANYCRLF) CR, LF, or CRLF only + (*BSR_UNICODE) any Unicode newline sequence + + These override the default and the options given to the compiling func- +- tion, but they can themselves be overridden by options given to a +- matching function. Note that these special settings, which are not +- Perl-compatible, are recognized only at the very start of a pattern, +- and that they must be in upper case. If more than one of them is +- present, the last one is used. They can be combined with a change of ++ tion, but they can themselves be overridden by options given to a ++ matching function. Note that these special settings, which are not ++ Perl-compatible, are recognized only at the very start of a pattern, ++ and that they must be in upper case. If more than one of them is ++ present, the last one is used. They can be combined with a change of + newline convention; for example, a pattern can start with: + + (*ANY)(*BSR_ANYCRLF) + +- They can also be combined with the (*UTF8), (*UTF16), (*UTF32), (*UTF) ++ They can also be combined with the (*UTF8), (*UTF16), (*UTF32), (*UTF) + or (*UCP) special sequences. Inside a character class, \R is treated as +- an unrecognized escape sequence, and so matches the letter "R" by ++ an unrecognized escape sequence, and so matches the letter "R" by + default, but causes an error if PCRE_EXTRA is set. + + Unicode character properties + + When PCRE is built with Unicode character property support, three addi- +- tional escape sequences that match characters with specific properties +- are available. When in 8-bit non-UTF-8 mode, these sequences are of +- course limited to testing characters whose codepoints are less than ++ tional escape sequences that match characters with specific properties ++ are available. When in 8-bit non-UTF-8 mode, these sequences are of ++ course limited to testing characters whose codepoints are less than + 256, but they do work in this mode. The extra escape sequences are: + + \p{xx} a character with the xx property + \P{xx} a character without the xx property + \X a Unicode extended grapheme cluster + +- The property names represented by xx above are limited to the Unicode ++ The property names represented by xx above are limited to the Unicode + script names, the general category properties, "Any", which matches any +- character (including newline), and some special PCRE properties +- (described in the next section). Other Perl properties such as "InMu- +- sicalSymbols" are not currently supported by PCRE. Note that \P{Any} ++ character (including newline), and some special PCRE properties ++ (described in the next section). Other Perl properties such as "InMu- ++ sicalSymbols" are not currently supported by PCRE. Note that \P{Any} + does not match any characters, so always causes a match failure. + + Sets of Unicode characters are defined as belonging to certain scripts. +- A character from one of these sets can be matched using a script name. ++ A character from one of these sets can be matched using a script name. + For example: + + \p{Greek} + \P{Han} + +- Those that are not part of an identified script are lumped together as ++ Those that are not part of an identified script are lumped together as + "Common". The current list of scripts is: + +- Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali, +- Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Car- ++ Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali, ++ Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Car- + ian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cunei- + form, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hiero- + glyphs, Elbasan, Ethiopic, Georgian, Glagolitic, Gothic, Grantha, +- Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, +- Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscrip- +- tional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li, +- Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Lin- +- ear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic, +- Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive, +- Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Myanmar, Nabataean, +- New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_North_Arabian, ++ Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, ++ Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscrip- ++ tional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li, ++ Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Lin- ++ ear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic, ++ Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive, ++ Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Myanmar, Nabataean, ++ New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_North_Arabian, + Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya, + Pahawh_Hmong, Palmyrene, Pau_Cin_Hau, Phags_Pa, Phoenician, +- Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Sha- +- vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac, +- Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu, +- Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi, ++ Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Sha- ++ vian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac, ++ Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu, ++ Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi, + Yi. + + Each character has exactly one Unicode general category property, spec- +- ified by a two-letter abbreviation. For compatibility with Perl, nega- +- tion can be specified by including a circumflex between the opening +- brace and the property name. For example, \p{^Lu} is the same as ++ ified by a two-letter abbreviation. For compatibility with Perl, nega- ++ tion can be specified by including a circumflex between the opening ++ brace and the property name. For example, \p{^Lu} is the same as + \P{Lu}. + + If only one letter is specified with \p or \P, it includes all the gen- +- eral category properties that start with that letter. In this case, in +- the absence of negation, the curly brackets in the escape sequence are ++ eral category properties that start with that letter. In this case, in ++ the absence of negation, the curly brackets in the escape sequence are + optional; these two examples have the same effect: + + \p{L} +@@ -5407,73 +5431,73 @@ BACKSLASH + Zp Paragraph separator + Zs Space separator + +- The special property L& is also supported: it matches a character that +- has the Lu, Ll, or Lt property, in other words, a letter that is not ++ The special property L& is also supported: it matches a character that ++ has the Lu, Ll, or Lt property, in other words, a letter that is not + classified as a modifier or "other". + +- The Cs (Surrogate) property applies only to characters in the range +- U+D800 to U+DFFF. Such characters are not valid in Unicode strings and +- so cannot be tested by PCRE, unless UTF validity checking has been ++ The Cs (Surrogate) property applies only to characters in the range ++ U+D800 to U+DFFF. Such characters are not valid in Unicode strings and ++ so cannot be tested by PCRE, unless UTF validity checking has been + turned off (see the discussion of PCRE_NO_UTF8_CHECK, +- PCRE_NO_UTF16_CHECK and PCRE_NO_UTF32_CHECK in the pcreapi page). Perl ++ PCRE_NO_UTF16_CHECK and PCRE_NO_UTF32_CHECK in the pcreapi page). Perl + does not support the Cs property. + +- The long synonyms for property names that Perl supports (such as +- \p{Letter}) are not supported by PCRE, nor is it permitted to prefix ++ The long synonyms for property names that Perl supports (such as ++ \p{Letter}) are not supported by PCRE, nor is it permitted to prefix + any of these properties with "Is". + + No character that is in the Unicode table has the Cn (unassigned) prop- + erty. Instead, this property is assumed for any code point that is not + in the Unicode table. + +- Specifying caseless matching does not affect these escape sequences. +- For example, \p{Lu} always matches only upper case letters. This is ++ Specifying caseless matching does not affect these escape sequences. ++ For example, \p{Lu} always matches only upper case letters. This is + different from the behaviour of current versions of Perl. + +- Matching characters by Unicode property is not fast, because PCRE has +- to do a multistage table lookup in order to find a character's prop- ++ Matching characters by Unicode property is not fast, because PCRE has ++ to do a multistage table lookup in order to find a character's prop- + erty. That is why the traditional escape sequences such as \d and \w do + not use Unicode properties in PCRE by default, though you can make them +- do so by setting the PCRE_UCP option or by starting the pattern with ++ do so by setting the PCRE_UCP option or by starting the pattern with + (*UCP). + + Extended grapheme clusters + +- The \X escape matches any number of Unicode characters that form an ++ The \X escape matches any number of Unicode characters that form an + "extended grapheme cluster", and treats the sequence as an atomic group +- (see below). Up to and including release 8.31, PCRE matched an ear- ++ (see below). Up to and including release 8.31, PCRE matched an ear- + lier, simpler definition that was equivalent to + + (?>\PM\pM*) + +- That is, it matched a character without the "mark" property, followed +- by zero or more characters with the "mark" property. Characters with +- the "mark" property are typically non-spacing accents that affect the ++ That is, it matched a character without the "mark" property, followed ++ by zero or more characters with the "mark" property. Characters with ++ the "mark" property are typically non-spacing accents that affect the + preceding character. + +- This simple definition was extended in Unicode to include more compli- +- cated kinds of composite character by giving each character a grapheme +- breaking property, and creating rules that use these properties to +- define the boundaries of extended grapheme clusters. In releases of ++ This simple definition was extended in Unicode to include more compli- ++ cated kinds of composite character by giving each character a grapheme ++ breaking property, and creating rules that use these properties to ++ define the boundaries of extended grapheme clusters. In releases of + PCRE later than 8.31, \X matches one of these clusters. + +- \X always matches at least one character. Then it decides whether to ++ \X always matches at least one character. Then it decides whether to + add additional characters according to the following rules for ending a + cluster: + + 1. End at the end of the subject string. + +- 2. Do not end between CR and LF; otherwise end after any control char- ++ 2. Do not end between CR and LF; otherwise end after any control char- + acter. + +- 3. Do not break Hangul (a Korean script) syllable sequences. Hangul +- characters are of five types: L, V, T, LV, and LVT. An L character may +- be followed by an L, V, LV, or LVT character; an LV or V character may ++ 3. Do not break Hangul (a Korean script) syllable sequences. Hangul ++ characters are of five types: L, V, T, LV, and LVT. An L character may ++ be followed by an L, V, LV, or LVT character; an LV or V character may + be followed by a V or T character; an LVT or T character may be follwed + only by a T character. + +- 4. Do not end before extending characters or spacing marks. Characters +- with the "mark" property always have the "extend" grapheme breaking ++ 4. Do not end before extending characters or spacing marks. Characters ++ with the "mark" property always have the "extend" grapheme breaking + property. + + 5. Do not end after prepend characters. +@@ -5482,9 +5506,9 @@ BACKSLASH + + PCRE's additional properties + +- As well as the standard Unicode properties described above, PCRE sup- +- ports four more that make it possible to convert traditional escape +- sequences such as \w and \s to use Unicode properties. PCRE uses these ++ As well as the standard Unicode properties described above, PCRE sup- ++ ports four more that make it possible to convert traditional escape ++ sequences such as \w and \s to use Unicode properties. PCRE uses these + non-standard, non-Perl properties internally when PCRE_UCP is set. How- + ever, they may also be used explicitly. These properties are: + +@@ -5493,54 +5517,54 @@ BACKSLASH + Xsp Any Perl space character + Xwd Any Perl "word" character + +- Xan matches characters that have either the L (letter) or the N (num- +- ber) property. Xps matches the characters tab, linefeed, vertical tab, +- form feed, or carriage return, and any other character that has the Z +- (separator) property. Xsp is the same as Xps; it used to exclude ver- +- tical tab, for Perl compatibility, but Perl changed, and so PCRE fol- +- lowed at release 8.34. Xwd matches the same characters as Xan, plus ++ Xan matches characters that have either the L (letter) or the N (num- ++ ber) property. Xps matches the characters tab, linefeed, vertical tab, ++ form feed, or carriage return, and any other character that has the Z ++ (separator) property. Xsp is the same as Xps; it used to exclude ver- ++ tical tab, for Perl compatibility, but Perl changed, and so PCRE fol- ++ lowed at release 8.34. Xwd matches the same characters as Xan, plus + underscore. + +- There is another non-standard property, Xuc, which matches any charac- +- ter that can be represented by a Universal Character Name in C++ and +- other programming languages. These are the characters $, @, ` (grave +- accent), and all characters with Unicode code points greater than or +- equal to U+00A0, except for the surrogates U+D800 to U+DFFF. Note that +- most base (ASCII) characters are excluded. (Universal Character Names +- are of the form \uHHHH or \UHHHHHHHH where H is a hexadecimal digit. ++ There is another non-standard property, Xuc, which matches any charac- ++ ter that can be represented by a Universal Character Name in C++ and ++ other programming languages. These are the characters $, @, ` (grave ++ accent), and all characters with Unicode code points greater than or ++ equal to U+00A0, except for the surrogates U+D800 to U+DFFF. Note that ++ most base (ASCII) characters are excluded. (Universal Character Names ++ are of the form \uHHHH or \UHHHHHHHH where H is a hexadecimal digit. + Note that the Xuc property does not match these sequences but the char- + acters that they represent.) + + Resetting the match start + +- The escape sequence \K causes any previously matched characters not to ++ The escape sequence \K causes any previously matched characters not to + be included in the final matched sequence. For example, the pattern: + + foo\Kbar + +- matches "foobar", but reports that it has matched "bar". This feature +- is similar to a lookbehind assertion (described below). However, in +- this case, the part of the subject before the real match does not have +- to be of fixed length, as lookbehind assertions do. The use of \K does +- not interfere with the setting of captured substrings. For example, ++ matches "foobar", but reports that it has matched "bar". This feature ++ is similar to a lookbehind assertion (described below). However, in ++ this case, the part of the subject before the real match does not have ++ to be of fixed length, as lookbehind assertions do. The use of \K does ++ not interfere with the setting of captured substrings. For example, + when the pattern + + (foo)\Kbar + + matches "foobar", the first substring is still set to "foo". + +- Perl documents that the use of \K within assertions is "not well +- defined". In PCRE, \K is acted upon when it occurs inside positive +- assertions, but is ignored in negative assertions. Note that when a +- pattern such as (?=ab\K) matches, the reported start of the match can ++ Perl documents that the use of \K within assertions is "not well ++ defined". In PCRE, \K is acted upon when it occurs inside positive ++ assertions, but is ignored in negative assertions. Note that when a ++ pattern such as (?=ab\K) matches, the reported start of the match can + be greater than the end of the match. + + Simple assertions + +- The final use of backslash is for certain simple assertions. An asser- +- tion specifies a condition that has to be met at a particular point in +- a match, without consuming any characters from the subject string. The +- use of subpatterns for more complicated assertions is described below. ++ The final use of backslash is for certain simple assertions. An asser- ++ tion specifies a condition that has to be met at a particular point in ++ a match, without consuming any characters from the subject string. The ++ use of subpatterns for more complicated assertions is described below. + The backslashed assertions are: + + \b matches at a word boundary +@@ -5551,161 +5575,161 @@ BACKSLASH + \z matches only at the end of the subject + \G matches at the first matching position in the subject + +- Inside a character class, \b has a different meaning; it matches the +- backspace character. If any other of these assertions appears in a +- character class, by default it matches the corresponding literal char- ++ Inside a character class, \b has a different meaning; it matches the ++ backspace character. If any other of these assertions appears in a ++ character class, by default it matches the corresponding literal char- + acter (for example, \B matches the letter B). However, if the +- PCRE_EXTRA option is set, an "invalid escape sequence" error is gener- ++ PCRE_EXTRA option is set, an "invalid escape sequence" error is gener- + ated instead. + +- A word boundary is a position in the subject string where the current +- character and the previous character do not both match \w or \W (i.e. +- one matches \w and the other matches \W), or the start or end of the +- string if the first or last character matches \w, respectively. In a +- UTF mode, the meanings of \w and \W can be changed by setting the +- PCRE_UCP option. When this is done, it also affects \b and \B. Neither +- PCRE nor Perl has a separate "start of word" or "end of word" metase- +- quence. However, whatever follows \b normally determines which it is. ++ A word boundary is a position in the subject string where the current ++ character and the previous character do not both match \w or \W (i.e. ++ one matches \w and the other matches \W), or the start or end of the ++ string if the first or last character matches \w, respectively. In a ++ UTF mode, the meanings of \w and \W can be changed by setting the ++ PCRE_UCP option. When this is done, it also affects \b and \B. Neither ++ PCRE nor Perl has a separate "start of word" or "end of word" metase- ++ quence. However, whatever follows \b normally determines which it is. + For example, the fragment \ba matches "a" at the start of a word. + +- The \A, \Z, and \z assertions differ from the traditional circumflex ++ The \A, \Z, and \z assertions differ from the traditional circumflex + and dollar (described in the next section) in that they only ever match +- at the very start and end of the subject string, whatever options are +- set. Thus, they are independent of multiline mode. These three asser- ++ at the very start and end of the subject string, whatever options are ++ set. Thus, they are independent of multiline mode. These three asser- + tions are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options, which +- affect only the behaviour of the circumflex and dollar metacharacters. +- However, if the startoffset argument of pcre_exec() is non-zero, indi- ++ affect only the behaviour of the circumflex and dollar metacharacters. ++ However, if the startoffset argument of pcre_exec() is non-zero, indi- + cating that matching is to start at a point other than the beginning of +- the subject, \A can never match. The difference between \Z and \z is ++ the subject, \A can never match. The difference between \Z and \z is + that \Z matches before a newline at the end of the string as well as at + the very end, whereas \z matches only at the end. + +- The \G assertion is true only when the current matching position is at +- the start point of the match, as specified by the startoffset argument +- of pcre_exec(). It differs from \A when the value of startoffset is +- non-zero. By calling pcre_exec() multiple times with appropriate argu- ++ The \G assertion is true only when the current matching position is at ++ the start point of the match, as specified by the startoffset argument ++ of pcre_exec(). It differs from \A when the value of startoffset is ++ non-zero. By calling pcre_exec() multiple times with appropriate argu- + ments, you can mimic Perl's /g option, and it is in this kind of imple- + mentation where \G can be useful. + +- Note, however, that PCRE's interpretation of \G, as the start of the ++ Note, however, that PCRE's interpretation of \G, as the start of the + current match, is subtly different from Perl's, which defines it as the +- end of the previous match. In Perl, these can be different when the +- previously matched string was empty. Because PCRE does just one match ++ end of the previous match. In Perl, these can be different when the ++ previously matched string was empty. Because PCRE does just one match + at a time, it cannot reproduce this behaviour. + +- If all the alternatives of a pattern begin with \G, the expression is ++ If all the alternatives of a pattern begin with \G, the expression is + anchored to the starting match position, and the "anchored" flag is set + in the compiled regular expression. + + + CIRCUMFLEX AND DOLLAR + +- The circumflex and dollar metacharacters are zero-width assertions. +- That is, they test for a particular condition being true without con- ++ The circumflex and dollar metacharacters are zero-width assertions. ++ That is, they test for a particular condition being true without con- + suming any characters from the subject string. + + Outside a character class, in the default matching mode, the circumflex +- character is an assertion that is true only if the current matching +- point is at the start of the subject string. If the startoffset argu- +- ment of pcre_exec() is non-zero, circumflex can never match if the +- PCRE_MULTILINE option is unset. Inside a character class, circumflex ++ character is an assertion that is true only if the current matching ++ point is at the start of the subject string. If the startoffset argu- ++ ment of pcre_exec() is non-zero, circumflex can never match if the ++ PCRE_MULTILINE option is unset. Inside a character class, circumflex + has an entirely different meaning (see below). + +- Circumflex need not be the first character of the pattern if a number +- of alternatives are involved, but it should be the first thing in each +- alternative in which it appears if the pattern is ever to match that +- branch. If all possible alternatives start with a circumflex, that is, +- if the pattern is constrained to match only at the start of the sub- +- ject, it is said to be an "anchored" pattern. (There are also other ++ Circumflex need not be the first character of the pattern if a number ++ of alternatives are involved, but it should be the first thing in each ++ alternative in which it appears if the pattern is ever to match that ++ branch. If all possible alternatives start with a circumflex, that is, ++ if the pattern is constrained to match only at the start of the sub- ++ ject, it is said to be an "anchored" pattern. (There are also other + constructs that can cause a pattern to be anchored.) + +- The dollar character is an assertion that is true only if the current +- matching point is at the end of the subject string, or immediately +- before a newline at the end of the string (by default). Note, however, +- that it does not actually match the newline. Dollar need not be the ++ The dollar character is an assertion that is true only if the current ++ matching point is at the end of the subject string, or immediately ++ before a newline at the end of the string (by default). Note, however, ++ that it does not actually match the newline. Dollar need not be the + last character of the pattern if a number of alternatives are involved, +- but it should be the last item in any branch in which it appears. Dol- ++ but it should be the last item in any branch in which it appears. Dol- + lar has no special meaning in a character class. + +- The meaning of dollar can be changed so that it matches only at the +- very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at ++ The meaning of dollar can be changed so that it matches only at the ++ very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at + compile time. This does not affect the \Z assertion. + + The meanings of the circumflex and dollar characters are changed if the +- PCRE_MULTILINE option is set. When this is the case, a circumflex +- matches immediately after internal newlines as well as at the start of +- the subject string. It does not match after a newline that ends the +- string. A dollar matches before any newlines in the string, as well as +- at the very end, when PCRE_MULTILINE is set. When newline is specified +- as the two-character sequence CRLF, isolated CR and LF characters do ++ PCRE_MULTILINE option is set. When this is the case, a circumflex ++ matches immediately after internal newlines as well as at the start of ++ the subject string. It does not match after a newline that ends the ++ string. A dollar matches before any newlines in the string, as well as ++ at the very end, when PCRE_MULTILINE is set. When newline is specified ++ as the two-character sequence CRLF, isolated CR and LF characters do + not indicate newlines. + +- For example, the pattern /^abc$/ matches the subject string "def\nabc" +- (where \n represents a newline) in multiline mode, but not otherwise. +- Consequently, patterns that are anchored in single line mode because +- all branches start with ^ are not anchored in multiline mode, and a +- match for circumflex is possible when the startoffset argument of +- pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if ++ For example, the pattern /^abc$/ matches the subject string "def\nabc" ++ (where \n represents a newline) in multiline mode, but not otherwise. ++ Consequently, patterns that are anchored in single line mode because ++ all branches start with ^ are not anchored in multiline mode, and a ++ match for circumflex is possible when the startoffset argument of ++ pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if + PCRE_MULTILINE is set. + +- Note that the sequences \A, \Z, and \z can be used to match the start +- and end of the subject in both modes, and if all branches of a pattern +- start with \A it is always anchored, whether or not PCRE_MULTILINE is ++ Note that the sequences \A, \Z, and \z can be used to match the start ++ and end of the subject in both modes, and if all branches of a pattern ++ start with \A it is always anchored, whether or not PCRE_MULTILINE is + set. + + + FULL STOP (PERIOD, DOT) AND \N + + Outside a character class, a dot in the pattern matches any one charac- +- ter in the subject string except (by default) a character that signi- ++ ter in the subject string except (by default) a character that signi- + fies the end of a line. + +- When a line ending is defined as a single character, dot never matches +- that character; when the two-character sequence CRLF is used, dot does +- not match CR if it is immediately followed by LF, but otherwise it +- matches all characters (including isolated CRs and LFs). When any Uni- +- code line endings are being recognized, dot does not match CR or LF or ++ When a line ending is defined as a single character, dot never matches ++ that character; when the two-character sequence CRLF is used, dot does ++ not match CR if it is immediately followed by LF, but otherwise it ++ matches all characters (including isolated CRs and LFs). When any Uni- ++ code line endings are being recognized, dot does not match CR or LF or + any of the other line ending characters. + +- The behaviour of dot with regard to newlines can be changed. If the +- PCRE_DOTALL option is set, a dot matches any one character, without ++ The behaviour of dot with regard to newlines can be changed. If the ++ PCRE_DOTALL option is set, a dot matches any one character, without + exception. If the two-character sequence CRLF is present in the subject + string, it takes two dots to match it. + +- The handling of dot is entirely independent of the handling of circum- +- flex and dollar, the only relationship being that they both involve ++ The handling of dot is entirely independent of the handling of circum- ++ flex and dollar, the only relationship being that they both involve + newlines. Dot has no special meaning in a character class. + +- The escape sequence \N behaves like a dot, except that it is not +- affected by the PCRE_DOTALL option. In other words, it matches any +- character except one that signifies the end of a line. Perl also uses ++ The escape sequence \N behaves like a dot, except that it is not ++ affected by the PCRE_DOTALL option. In other words, it matches any ++ character except one that signifies the end of a line. Perl also uses + \N to match characters by name; PCRE does not support this. + + + MATCHING A SINGLE DATA UNIT + +- Outside a character class, the escape sequence \C matches any one data +- unit, whether or not a UTF mode is set. In the 8-bit library, one data +- unit is one byte; in the 16-bit library it is a 16-bit unit; in the +- 32-bit library it is a 32-bit unit. Unlike a dot, \C always matches +- line-ending characters. The feature is provided in Perl in order to ++ Outside a character class, the escape sequence \C matches any one data ++ unit, whether or not a UTF mode is set. In the 8-bit library, one data ++ unit is one byte; in the 16-bit library it is a 16-bit unit; in the ++ 32-bit library it is a 32-bit unit. Unlike a dot, \C always matches ++ line-ending characters. The feature is provided in Perl in order to + match individual bytes in UTF-8 mode, but it is unclear how it can use- +- fully be used. Because \C breaks up characters into individual data +- units, matching one unit with \C in a UTF mode means that the rest of ++ fully be used. Because \C breaks up characters into individual data ++ units, matching one unit with \C in a UTF mode means that the rest of + the string may start with a malformed UTF character. This has undefined + results, because PCRE assumes that it is dealing with valid UTF strings +- (and by default it checks this at the start of processing unless the +- PCRE_NO_UTF8_CHECK, PCRE_NO_UTF16_CHECK or PCRE_NO_UTF32_CHECK option ++ (and by default it checks this at the start of processing unless the ++ PCRE_NO_UTF8_CHECK, PCRE_NO_UTF16_CHECK or PCRE_NO_UTF32_CHECK option + is used). + +- PCRE does not allow \C to appear in lookbehind assertions (described +- below) in a UTF mode, because this would make it impossible to calcu- ++ PCRE does not allow \C to appear in lookbehind assertions (described ++ below) in a UTF mode, because this would make it impossible to calcu- + late the length of the lookbehind. + + In general, the \C escape sequence is best avoided. However, one way of +- using it that avoids the problem of malformed UTF characters is to use +- a lookahead to check the length of the next character, as in this pat- +- tern, which could be used with a UTF-8 string (ignore white space and ++ using it that avoids the problem of malformed UTF characters is to use ++ a lookahead to check the length of the next character, as in this pat- ++ tern, which could be used with a UTF-8 string (ignore white space and + line breaks): + + (?| (?=[\x00-\x7f])(\C) | +@@ -5713,11 +5737,11 @@ MATCHING A SINGLE DATA UNIT + (?=[\x{800}-\x{ffff}])(\C)(\C)(\C) | + (?=[\x{10000}-\x{1fffff}])(\C)(\C)(\C)(\C)) + +- A group that starts with (?| resets the capturing parentheses numbers +- in each alternative (see "Duplicate Subpattern Numbers" below). The +- assertions at the start of each branch check the next UTF-8 character +- for values whose encoding uses 1, 2, 3, or 4 bytes, respectively. The +- character's individual bytes are then captured by the appropriate num- ++ A group that starts with (?| resets the capturing parentheses numbers ++ in each alternative (see "Duplicate Subpattern Numbers" below). The ++ assertions at the start of each branch check the next UTF-8 character ++ for values whose encoding uses 1, 2, 3, or 4 bytes, respectively. The ++ character's individual bytes are then captured by the appropriate num- + ber of groups. + + +@@ -5727,109 +5751,109 @@ SQUARE BRACKETS AND CHARACTER CLASSES + closing square bracket. A closing square bracket on its own is not spe- + cial by default. However, if the PCRE_JAVASCRIPT_COMPAT option is set, + a lone closing square bracket causes a compile-time error. If a closing +- square bracket is required as a member of the class, it should be the +- first data character in the class (after an initial circumflex, if ++ square bracket is required as a member of the class, it should be the ++ first data character in the class (after an initial circumflex, if + present) or escaped with a backslash. + +- A character class matches a single character in the subject. In a UTF +- mode, the character may be more than one data unit long. A matched ++ A character class matches a single character in the subject. In a UTF ++ mode, the character may be more than one data unit long. A matched + character must be in the set of characters defined by the class, unless +- the first character in the class definition is a circumflex, in which ++ the first character in the class definition is a circumflex, in which + case the subject character must not be in the set defined by the class. +- If a circumflex is actually required as a member of the class, ensure ++ If a circumflex is actually required as a member of the class, ensure + it is not the first character, or escape it with a backslash. + +- For example, the character class [aeiou] matches any lower case vowel, +- while [^aeiou] matches any character that is not a lower case vowel. ++ For example, the character class [aeiou] matches any lower case vowel, ++ while [^aeiou] matches any character that is not a lower case vowel. + Note that a circumflex is just a convenient notation for specifying the +- characters that are in the class by enumerating those that are not. A +- class that starts with a circumflex is not an assertion; it still con- +- sumes a character from the subject string, and therefore it fails if ++ characters that are in the class by enumerating those that are not. A ++ class that starts with a circumflex is not an assertion; it still con- ++ sumes a character from the subject string, and therefore it fails if + the current pointer is at the end of the string. + + In UTF-8 (UTF-16, UTF-32) mode, characters with values greater than 255 +- (0xffff) can be included in a class as a literal string of data units, ++ (0xffff) can be included in a class as a literal string of data units, + or by using the \x{ escaping mechanism. + +- When caseless matching is set, any letters in a class represent both +- their upper case and lower case versions, so for example, a caseless +- [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not +- match "A", whereas a caseful version would. In a UTF mode, PCRE always +- understands the concept of case for characters whose values are less +- than 128, so caseless matching is always possible. For characters with +- higher values, the concept of case is supported if PCRE is compiled +- with Unicode property support, but not otherwise. If you want to use +- caseless matching in a UTF mode for characters 128 and above, you must +- ensure that PCRE is compiled with Unicode property support as well as ++ When caseless matching is set, any letters in a class represent both ++ their upper case and lower case versions, so for example, a caseless ++ [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not ++ match "A", whereas a caseful version would. In a UTF mode, PCRE always ++ understands the concept of case for characters whose values are less ++ than 128, so caseless matching is always possible. For characters with ++ higher values, the concept of case is supported if PCRE is compiled ++ with Unicode property support, but not otherwise. If you want to use ++ caseless matching in a UTF mode for characters 128 and above, you must ++ ensure that PCRE is compiled with Unicode property support as well as + with UTF support. + +- Characters that might indicate line breaks are never treated in any +- special way when matching character classes, whatever line-ending +- sequence is in use, and whatever setting of the PCRE_DOTALL and ++ Characters that might indicate line breaks are never treated in any ++ special way when matching character classes, whatever line-ending ++ sequence is in use, and whatever setting of the PCRE_DOTALL and + PCRE_MULTILINE options is used. A class such as [^a] always matches one + of these characters. + +- The minus (hyphen) character can be used to specify a range of charac- +- ters in a character class. For example, [d-m] matches any letter +- between d and m, inclusive. If a minus character is required in a +- class, it must be escaped with a backslash or appear in a position +- where it cannot be interpreted as indicating a range, typically as the ++ The minus (hyphen) character can be used to specify a range of charac- ++ ters in a character class. For example, [d-m] matches any letter ++ between d and m, inclusive. If a minus character is required in a ++ class, it must be escaped with a backslash or appear in a position ++ where it cannot be interpreted as indicating a range, typically as the + first or last character in the class, or immediately after a range. For +- example, [b-d-z] matches letters in the range b to d, a hyphen charac- ++ example, [b-d-z] matches letters in the range b to d, a hyphen charac- + ter, or z. + + It is not possible to have the literal character "]" as the end charac- +- ter of a range. A pattern such as [W-]46] is interpreted as a class of +- two characters ("W" and "-") followed by a literal string "46]", so it +- would match "W46]" or "-46]". However, if the "]" is escaped with a +- backslash it is interpreted as the end of range, so [W-\]46] is inter- +- preted as a class containing a range followed by two other characters. +- The octal or hexadecimal representation of "]" can also be used to end ++ ter of a range. A pattern such as [W-]46] is interpreted as a class of ++ two characters ("W" and "-") followed by a literal string "46]", so it ++ would match "W46]" or "-46]". However, if the "]" is escaped with a ++ backslash it is interpreted as the end of range, so [W-\]46] is inter- ++ preted as a class containing a range followed by two other characters. ++ The octal or hexadecimal representation of "]" can also be used to end + a range. + +- An error is generated if a POSIX character class (see below) or an +- escape sequence other than one that defines a single character appears +- at a point where a range ending character is expected. For example, ++ An error is generated if a POSIX character class (see below) or an ++ escape sequence other than one that defines a single character appears ++ at a point where a range ending character is expected. For example, + [z-\xff] is valid, but [A-\d] and [A-[:digit:]] are not. + +- Ranges operate in the collating sequence of character values. They can +- also be used for characters specified numerically, for example +- [\000-\037]. Ranges can include any characters that are valid for the ++ Ranges operate in the collating sequence of character values. They can ++ also be used for characters specified numerically, for example ++ [\000-\037]. Ranges can include any characters that are valid for the + current mode. + + If a range that includes letters is used when caseless matching is set, + it matches the letters in either case. For example, [W-c] is equivalent +- to [][\\^_`wxyzabc], matched caselessly, and in a non-UTF mode, if +- character tables for a French locale are in use, [\xc8-\xcb] matches +- accented E characters in both cases. In UTF modes, PCRE supports the +- concept of case for characters with values greater than 128 only when ++ to [][\\^_`wxyzabc], matched caselessly, and in a non-UTF mode, if ++ character tables for a French locale are in use, [\xc8-\xcb] matches ++ accented E characters in both cases. In UTF modes, PCRE supports the ++ concept of case for characters with values greater than 128 only when + it is compiled with Unicode property support. + +- The character escape sequences \d, \D, \h, \H, \p, \P, \s, \S, \v, \V, ++ The character escape sequences \d, \D, \h, \H, \p, \P, \s, \S, \v, \V, + \w, and \W may appear in a character class, and add the characters that +- they match to the class. For example, [\dABCDEF] matches any hexadeci- +- mal digit. In UTF modes, the PCRE_UCP option affects the meanings of +- \d, \s, \w and their upper case partners, just as it does when they +- appear outside a character class, as described in the section entitled ++ they match to the class. For example, [\dABCDEF] matches any hexadeci- ++ mal digit. In UTF modes, the PCRE_UCP option affects the meanings of ++ \d, \s, \w and their upper case partners, just as it does when they ++ appear outside a character class, as described in the section entitled + "Generic character types" above. The escape sequence \b has a different +- meaning inside a character class; it matches the backspace character. +- The sequences \B, \N, \R, and \X are not special inside a character +- class. Like any other unrecognized escape sequences, they are treated +- as the literal characters "B", "N", "R", and "X" by default, but cause ++ meaning inside a character class; it matches the backspace character. ++ The sequences \B, \N, \R, and \X are not special inside a character ++ class. Like any other unrecognized escape sequences, they are treated ++ as the literal characters "B", "N", "R", and "X" by default, but cause + an error if the PCRE_EXTRA option is set. + +- A circumflex can conveniently be used with the upper case character +- types to specify a more restricted set of characters than the matching +- lower case type. For example, the class [^\W_] matches any letter or ++ A circumflex can conveniently be used with the upper case character ++ types to specify a more restricted set of characters than the matching ++ lower case type. For example, the class [^\W_] matches any letter or + digit, but not underscore, whereas [\w] includes underscore. A positive + character class should be read as "something OR something OR ..." and a + negative class as "NOT something AND NOT something AND NOT ...". + +- The only metacharacters that are recognized in character classes are +- backslash, hyphen (only where it can be interpreted as specifying a +- range), circumflex (only at the start), opening square bracket (only +- when it can be interpreted as introducing a POSIX class name, or for a +- special compatibility feature - see the next two sections), and the ++ The only metacharacters that are recognized in character classes are ++ backslash, hyphen (only where it can be interpreted as specifying a ++ range), circumflex (only at the start), opening square bracket (only ++ when it can be interpreted as introducing a POSIX class name, or for a ++ special compatibility feature - see the next two sections), and the + terminating closing square bracket. However, escaping other non- + alphanumeric characters does no harm. + +@@ -5837,7 +5861,7 @@ SQUARE BRACKETS AND CHARACTER CLASSES + POSIX CHARACTER CLASSES + + Perl supports the POSIX notation for character classes. This uses names +- enclosed by [: and :] within the enclosing square brackets. PCRE also ++ enclosed by [: and :] within the enclosing square brackets. PCRE also + supports this notation. For example, + + [01[:alpha:]%] +@@ -5860,28 +5884,28 @@ POSIX CHARACTER CLASSES + word "word" characters (same as \w) + xdigit hexadecimal digits + +- The default "space" characters are HT (9), LF (10), VT (11), FF (12), +- CR (13), and space (32). If locale-specific matching is taking place, +- the list of space characters may be different; there may be fewer or ++ The default "space" characters are HT (9), LF (10), VT (11), FF (12), ++ CR (13), and space (32). If locale-specific matching is taking place, ++ the list of space characters may be different; there may be fewer or + more of them. "Space" used to be different to \s, which did not include + VT, for Perl compatibility. However, Perl changed at release 5.18, and +- PCRE followed at release 8.34. "Space" and \s now match the same set ++ PCRE followed at release 8.34. "Space" and \s now match the same set + of characters. + +- The name "word" is a Perl extension, and "blank" is a GNU extension +- from Perl 5.8. Another Perl extension is negation, which is indicated ++ The name "word" is a Perl extension, and "blank" is a GNU extension ++ from Perl 5.8. Another Perl extension is negation, which is indicated + by a ^ character after the colon. For example, + + [12[:^digit:]] + +- matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the ++ matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the + POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but + these are not supported, and an error is given if they are encountered. + + By default, characters with values greater than 128 do not match any of +- the POSIX character classes. However, if the PCRE_UCP option is passed +- to pcre_compile(), some of the classes are changed so that Unicode +- character properties are used. This is achieved by replacing certain ++ the POSIX character classes. However, if the PCRE_UCP option is passed ++ to pcre_compile(), some of the classes are changed so that Unicode ++ character properties are used. This is achieved by replacing certain + POSIX classes by other sequences, as follows: + + [:alnum:] becomes \p{Xan} +@@ -5893,10 +5917,10 @@ POSIX CHARACTER CLASSES + [:upper:] becomes \p{Lu} + [:word:] becomes \p{Xwd} + +- Negated versions, such as [:^alpha:] use \P instead of \p. Three other ++ Negated versions, such as [:^alpha:] use \P instead of \p. Three other + POSIX classes are handled specially in UCP mode: + +- [:graph:] This matches characters that have glyphs that mark the page ++ [:graph:] This matches characters that have glyphs that mark the page + when printed. In Unicode property terms, it matches all char- + acters with the L, M, N, P, S, or Cf properties, except for: + +@@ -5905,58 +5929,58 @@ POSIX CHARACTER CLASSES + U+2066 - U+2069 Various "isolate"s + + +- [:print:] This matches the same characters as [:graph:] plus space +- characters that are not controls, that is, characters with ++ [:print:] This matches the same characters as [:graph:] plus space ++ characters that are not controls, that is, characters with + the Zs property. + + [:punct:] This matches all characters that have the Unicode P (punctua- +- tion) property, plus those characters whose code points are ++ tion) property, plus those characters whose code points are + less than 128 that have the S (Symbol) property. + +- The other POSIX classes are unchanged, and match only characters with ++ The other POSIX classes are unchanged, and match only characters with + code points less than 128. + + + COMPATIBILITY FEATURE FOR WORD BOUNDARIES + +- In the POSIX.2 compliant library that was included in 4.4BSD Unix, the +- ugly syntax [[:<:]] and [[:>:]] is used for matching "start of word" ++ In the POSIX.2 compliant library that was included in 4.4BSD Unix, the ++ ugly syntax [[:<:]] and [[:>:]] is used for matching "start of word" + and "end of word". PCRE treats these items as follows: + + [[:<:]] is converted to \b(?=\w) + [[:>:]] is converted to \b(?<=\w) + + Only these exact character sequences are recognized. A sequence such as +- [a[:<:]b] provokes error for an unrecognized POSIX class name. This +- support is not compatible with Perl. It is provided to help migrations ++ [a[:<:]b] provokes error for an unrecognized POSIX class name. This ++ support is not compatible with Perl. It is provided to help migrations + from other environments, and is best not used in any new patterns. Note +- that \b matches at the start and the end of a word (see "Simple asser- +- tions" above), and in a Perl-style pattern the preceding or following +- character normally shows which is wanted, without the need for the +- assertions that are used above in order to give exactly the POSIX be- ++ that \b matches at the start and the end of a word (see "Simple asser- ++ tions" above), and in a Perl-style pattern the preceding or following ++ character normally shows which is wanted, without the need for the ++ assertions that are used above in order to give exactly the POSIX be- + haviour. + + + VERTICAL BAR + +- Vertical bar characters are used to separate alternative patterns. For ++ Vertical bar characters are used to separate alternative patterns. For + example, the pattern + + gilbert|sullivan + +- matches either "gilbert" or "sullivan". Any number of alternatives may +- appear, and an empty alternative is permitted (matching the empty ++ matches either "gilbert" or "sullivan". Any number of alternatives may ++ appear, and an empty alternative is permitted (matching the empty + string). The matching process tries each alternative in turn, from left +- to right, and the first one that succeeds is used. If the alternatives +- are within a subpattern (defined below), "succeeds" means matching the ++ to right, and the first one that succeeds is used. If the alternatives ++ are within a subpattern (defined below), "succeeds" means matching the + rest of the main pattern as well as the alternative in the subpattern. + + + INTERNAL OPTION SETTING + +- The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and +- PCRE_EXTENDED options (which are Perl-compatible) can be changed from +- within the pattern by a sequence of Perl option letters enclosed ++ The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and ++ PCRE_EXTENDED options (which are Perl-compatible) can be changed from ++ within the pattern by a sequence of Perl option letters enclosed + between "(?" and ")". The option letters are + + i for PCRE_CASELESS +@@ -5966,51 +5990,51 @@ INTERNAL OPTION SETTING + + For example, (?im) sets caseless, multiline matching. It is also possi- + ble to unset these options by preceding the letter with a hyphen, and a +- combined setting and unsetting such as (?im-sx), which sets PCRE_CASE- +- LESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, +- is also permitted. If a letter appears both before and after the ++ combined setting and unsetting such as (?im-sx), which sets PCRE_CASE- ++ LESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, ++ is also permitted. If a letter appears both before and after the + hyphen, the option is unset. + +- The PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA +- can be changed in the same way as the Perl-compatible options by using ++ The PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA ++ can be changed in the same way as the Perl-compatible options by using + the characters J, U and X respectively. + +- When one of these option changes occurs at top level (that is, not +- inside subpattern parentheses), the change applies to the remainder of ++ When one of these option changes occurs at top level (that is, not ++ inside subpattern parentheses), the change applies to the remainder of + the pattern that follows. If the change is placed right at the start of + a pattern, PCRE extracts it into the global options (and it will there- + fore show up in data extracted by the pcre_fullinfo() function). + +- An option change within a subpattern (see below for a description of +- subpatterns) affects only that part of the subpattern that follows it, ++ An option change within a subpattern (see below for a description of ++ subpatterns) affects only that part of the subpattern that follows it, + so + + (a(?i)b)c + + matches abc and aBc and no other strings (assuming PCRE_CASELESS is not +- used). By this means, options can be made to have different settings +- in different parts of the pattern. Any changes made in one alternative +- do carry on into subsequent branches within the same subpattern. For ++ used). By this means, options can be made to have different settings ++ in different parts of the pattern. Any changes made in one alternative ++ do carry on into subsequent branches within the same subpattern. For + example, + + (a(?i)b|c) + +- matches "ab", "aB", "c", and "C", even though when matching "C" the +- first branch is abandoned before the option setting. This is because +- the effects of option settings happen at compile time. There would be ++ matches "ab", "aB", "c", and "C", even though when matching "C" the ++ first branch is abandoned before the option setting. This is because ++ the effects of option settings happen at compile time. There would be + some very weird behaviour otherwise. + +- Note: There are other PCRE-specific options that can be set by the +- application when the compiling or matching functions are called. In +- some cases the pattern can contain special leading sequences such as +- (*CRLF) to override what the application has set or what has been +- defaulted. Details are given in the section entitled "Newline +- sequences" above. There are also the (*UTF8), (*UTF16),(*UTF32), and +- (*UCP) leading sequences that can be used to set UTF and Unicode prop- +- erty modes; they are equivalent to setting the PCRE_UTF8, PCRE_UTF16, +- PCRE_UTF32 and the PCRE_UCP options, respectively. The (*UTF) sequence +- is a generic version that can be used with any of the libraries. How- +- ever, the application can set the PCRE_NEVER_UTF option, which locks ++ Note: There are other PCRE-specific options that can be set by the ++ application when the compiling or matching functions are called. In ++ some cases the pattern can contain special leading sequences such as ++ (*CRLF) to override what the application has set or what has been ++ defaulted. Details are given in the section entitled "Newline ++ sequences" above. There are also the (*UTF8), (*UTF16),(*UTF32), and ++ (*UCP) leading sequences that can be used to set UTF and Unicode prop- ++ erty modes; they are equivalent to setting the PCRE_UTF8, PCRE_UTF16, ++ PCRE_UTF32 and the PCRE_UCP options, respectively. The (*UTF) sequence ++ is a generic version that can be used with any of the libraries. How- ++ ever, the application can set the PCRE_NEVER_UTF option, which locks + out the use of the (*UTF) sequences. + + +@@ -6023,18 +6047,18 @@ SUBPATTERNS + + cat(aract|erpillar|) + +- matches "cataract", "caterpillar", or "cat". Without the parentheses, ++ matches "cataract", "caterpillar", or "cat". Without the parentheses, + it would match "cataract", "erpillar" or an empty string. + +- 2. It sets up the subpattern as a capturing subpattern. This means +- that, when the whole pattern matches, that portion of the subject ++ 2. It sets up the subpattern as a capturing subpattern. This means ++ that, when the whole pattern matches, that portion of the subject + string that matched the subpattern is passed back to the caller via the +- ovector argument of the matching function. (This applies only to the +- traditional matching functions; the DFA matching functions do not sup- ++ ovector argument of the matching function. (This applies only to the ++ traditional matching functions; the DFA matching functions do not sup- + port capturing.) + + Opening parentheses are counted from left to right (starting from 1) to +- obtain numbers for the capturing subpatterns. For example, if the ++ obtain numbers for the capturing subpatterns. For example, if the + string "the red king" is matched against the pattern + + the ((red|white) (king|queen)) +@@ -6042,12 +6066,12 @@ SUBPATTERNS + the captured substrings are "red king", "red", and "king", and are num- + bered 1, 2, and 3, respectively. + +- The fact that plain parentheses fulfil two functions is not always +- helpful. There are often times when a grouping subpattern is required +- without a capturing requirement. If an opening parenthesis is followed +- by a question mark and a colon, the subpattern does not do any captur- +- ing, and is not counted when computing the number of any subsequent +- capturing subpatterns. For example, if the string "the white queen" is ++ The fact that plain parentheses fulfil two functions is not always ++ helpful. There are often times when a grouping subpattern is required ++ without a capturing requirement. If an opening parenthesis is followed ++ by a question mark and a colon, the subpattern does not do any captur- ++ ing, and is not counted when computing the number of any subsequent ++ capturing subpatterns. For example, if the string "the white queen" is + matched against the pattern + + the ((?:red|white) (king|queen)) +@@ -6055,37 +6079,37 @@ SUBPATTERNS + the captured substrings are "white queen" and "queen", and are numbered + 1 and 2. The maximum number of capturing subpatterns is 65535. + +- As a convenient shorthand, if any option settings are required at the +- start of a non-capturing subpattern, the option letters may appear ++ As a convenient shorthand, if any option settings are required at the ++ start of a non-capturing subpattern, the option letters may appear + between the "?" and the ":". Thus the two patterns + + (?i:saturday|sunday) + (?:(?i)saturday|sunday) + + match exactly the same set of strings. Because alternative branches are +- tried from left to right, and options are not reset until the end of +- the subpattern is reached, an option setting in one branch does affect +- subsequent branches, so the above patterns match "SUNDAY" as well as ++ tried from left to right, and options are not reset until the end of ++ the subpattern is reached, an option setting in one branch does affect ++ subsequent branches, so the above patterns match "SUNDAY" as well as + "Saturday". + + + DUPLICATE SUBPATTERN NUMBERS + + Perl 5.10 introduced a feature whereby each alternative in a subpattern +- uses the same numbers for its capturing parentheses. Such a subpattern +- starts with (?| and is itself a non-capturing subpattern. For example, ++ uses the same numbers for its capturing parentheses. Such a subpattern ++ starts with (?| and is itself a non-capturing subpattern. For example, + consider this pattern: + + (?|(Sat)ur|(Sun))day + +- Because the two alternatives are inside a (?| group, both sets of cap- +- turing parentheses are numbered one. Thus, when the pattern matches, +- you can look at captured substring number one, whichever alternative +- matched. This construct is useful when you want to capture part, but ++ Because the two alternatives are inside a (?| group, both sets of cap- ++ turing parentheses are numbered one. Thus, when the pattern matches, ++ you can look at captured substring number one, whichever alternative ++ matched. This construct is useful when you want to capture part, but + not all, of one of a number of alternatives. Inside a (?| group, paren- +- theses are numbered as usual, but the number is reset at the start of +- each branch. The numbers of any capturing parentheses that follow the +- subpattern start after the highest number used in any branch. The fol- ++ theses are numbered as usual, but the number is reset at the start of ++ each branch. The numbers of any capturing parentheses that follow the ++ subpattern start after the highest number used in any branch. The fol- + lowing example is taken from the Perl documentation. The numbers under- + neath show in which buffer the captured content will be stored. + +@@ -6093,58 +6117,58 @@ DUPLICATE SUBPATTERN NUMBERS + / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x + # 1 2 2 3 2 3 4 + +- A back reference to a numbered subpattern uses the most recent value +- that is set for that number by any subpattern. The following pattern ++ A back reference to a numbered subpattern uses the most recent value ++ that is set for that number by any subpattern. The following pattern + matches "abcabc" or "defdef": + + /(?|(abc)|(def))\1/ + +- In contrast, a subroutine call to a numbered subpattern always refers +- to the first one in the pattern with the given number. The following ++ In contrast, a subroutine call to a numbered subpattern always refers ++ to the first one in the pattern with the given number. The following + pattern matches "abcabc" or "defabc": + + /(?|(abc)|(def))(?1)/ + +- If a condition test for a subpattern's having matched refers to a non- +- unique number, the test is true if any of the subpatterns of that num- ++ If a condition test for a subpattern's having matched refers to a non- ++ unique number, the test is true if any of the subpatterns of that num- + ber have matched. + +- An alternative approach to using this "branch reset" feature is to use ++ An alternative approach to using this "branch reset" feature is to use + duplicate named subpatterns, as described in the next section. + + + NAMED SUBPATTERNS + +- Identifying capturing parentheses by number is simple, but it can be +- very hard to keep track of the numbers in complicated regular expres- +- sions. Furthermore, if an expression is modified, the numbers may +- change. To help with this difficulty, PCRE supports the naming of sub- ++ Identifying capturing parentheses by number is simple, but it can be ++ very hard to keep track of the numbers in complicated regular expres- ++ sions. Furthermore, if an expression is modified, the numbers may ++ change. To help with this difficulty, PCRE supports the naming of sub- + patterns. This feature was not added to Perl until release 5.10. Python +- had the feature earlier, and PCRE introduced it at release 4.0, using +- the Python syntax. PCRE now supports both the Perl and the Python syn- +- tax. Perl allows identically numbered subpatterns to have different ++ had the feature earlier, and PCRE introduced it at release 4.0, using ++ the Python syntax. PCRE now supports both the Perl and the Python syn- ++ tax. Perl allows identically numbered subpatterns to have different + names, but PCRE does not. + +- In PCRE, a subpattern can be named in one of three ways: (?<name>...) +- or (?'name'...) as in Perl, or (?P<name>...) as in Python. References +- to capturing parentheses from other parts of the pattern, such as back +- references, recursion, and conditions, can be made by name as well as ++ In PCRE, a subpattern can be named in one of three ways: (?<name>...) ++ or (?'name'...) as in Perl, or (?P<name>...) as in Python. References ++ to capturing parentheses from other parts of the pattern, such as back ++ references, recursion, and conditions, can be made by name as well as + by number. + +- Names consist of up to 32 alphanumeric characters and underscores, but +- must start with a non-digit. Named capturing parentheses are still +- allocated numbers as well as names, exactly as if the names were not +- present. The PCRE API provides function calls for extracting the name- +- to-number translation table from a compiled pattern. There is also a ++ Names consist of up to 32 alphanumeric characters and underscores, but ++ must start with a non-digit. Named capturing parentheses are still ++ allocated numbers as well as names, exactly as if the names were not ++ present. The PCRE API provides function calls for extracting the name- ++ to-number translation table from a compiled pattern. There is also a + convenience function for extracting a captured substring by name. + +- By default, a name must be unique within a pattern, but it is possible ++ By default, a name must be unique within a pattern, but it is possible + to relax this constraint by setting the PCRE_DUPNAMES option at compile +- time. (Duplicate names are also always permitted for subpatterns with +- the same number, set up as described in the previous section.) Dupli- +- cate names can be useful for patterns where only one instance of the +- named parentheses can match. Suppose you want to match the name of a +- weekday, either as a 3-letter abbreviation or as the full name, and in ++ time. (Duplicate names are also always permitted for subpatterns with ++ the same number, set up as described in the previous section.) Dupli- ++ cate names can be useful for patterns where only one instance of the ++ named parentheses can match. Suppose you want to match the name of a ++ weekday, either as a 3-letter abbreviation or as the full name, and in + both cases you want to extract the abbreviation. This pattern (ignoring + the line breaks) does the job: + +@@ -6154,18 +6178,18 @@ NAMED SUBPATTERNS + (?<DN>Thu)(?:rsday)?| + (?<DN>Sat)(?:urday)? + +- There are five capturing substrings, but only one is ever set after a ++ There are five capturing substrings, but only one is ever set after a + match. (An alternative way of solving this problem is to use a "branch + reset" subpattern, as described in the previous section.) + +- The convenience function for extracting the data by name returns the +- substring for the first (and in this example, the only) subpattern of +- that name that matched. This saves searching to find which numbered ++ The convenience function for extracting the data by name returns the ++ substring for the first (and in this example, the only) subpattern of ++ that name that matched. This saves searching to find which numbered + subpattern it was. + +- If you make a back reference to a non-unique named subpattern from +- elsewhere in the pattern, the subpatterns to which the name refers are +- checked in the order in which they appear in the overall pattern. The ++ If you make a back reference to a non-unique named subpattern from ++ elsewhere in the pattern, the subpatterns to which the name refers are ++ checked in the order in which they appear in the overall pattern. The + first one that is set is used for the reference. For example, this pat- + tern matches both "foofoo" and "barbar" but not "foobar" or "barfoo": + +@@ -6173,29 +6197,29 @@ NAMED SUBPATTERNS + + + If you make a subroutine call to a non-unique named subpattern, the one +- that corresponds to the first occurrence of the name is used. In the ++ that corresponds to the first occurrence of the name is used. In the + absence of duplicate numbers (see the previous section) this is the one + with the lowest number. + + If you use a named reference in a condition test (see the section about + conditions below), either to check whether a subpattern has matched, or +- to check for recursion, all subpatterns with the same name are tested. +- If the condition is true for any one of them, the overall condition is +- true. This is the same behaviour as testing by number. For further +- details of the interfaces for handling named subpatterns, see the ++ to check for recursion, all subpatterns with the same name are tested. ++ If the condition is true for any one of them, the overall condition is ++ true. This is the same behaviour as testing by number. For further ++ details of the interfaces for handling named subpatterns, see the + pcreapi documentation. + + Warning: You cannot use different names to distinguish between two sub- +- patterns with the same number because PCRE uses only the numbers when ++ patterns with the same number because PCRE uses only the numbers when + matching. For this reason, an error is given at compile time if differ- +- ent names are given to subpatterns with the same number. However, you ++ ent names are given to subpatterns with the same number. However, you + can always give the same name to subpatterns with the same number, even + when PCRE_DUPNAMES is not set. + + + REPETITION + +- Repetition is specified by quantifiers, which can follow any of the ++ Repetition is specified by quantifiers, which can follow any of the + following items: + + a literal data character +@@ -6209,17 +6233,17 @@ REPETITION + a parenthesized subpattern (including assertions) + a subroutine call to a subpattern (recursive or otherwise) + +- The general repetition quantifier specifies a minimum and maximum num- +- ber of permitted matches, by giving the two numbers in curly brackets +- (braces), separated by a comma. The numbers must be less than 65536, ++ The general repetition quantifier specifies a minimum and maximum num- ++ ber of permitted matches, by giving the two numbers in curly brackets ++ (braces), separated by a comma. The numbers must be less than 65536, + and the first must be less than or equal to the second. For example: + + z{2,4} + +- matches "zz", "zzz", or "zzzz". A closing brace on its own is not a +- special character. If the second number is omitted, but the comma is +- present, there is no upper limit; if the second number and the comma +- are both omitted, the quantifier specifies an exact number of required ++ matches "zz", "zzz", or "zzzz". A closing brace on its own is not a ++ special character. If the second number is omitted, but the comma is ++ present, there is no upper limit; if the second number and the comma ++ are both omitted, the quantifier specifies an exact number of required + matches. Thus + + [aeiou]{3,} +@@ -6228,50 +6252,50 @@ REPETITION + + \d{8} + +- matches exactly 8 digits. An opening curly bracket that appears in a +- position where a quantifier is not allowed, or one that does not match +- the syntax of a quantifier, is taken as a literal character. For exam- ++ matches exactly 8 digits. An opening curly bracket that appears in a ++ position where a quantifier is not allowed, or one that does not match ++ the syntax of a quantifier, is taken as a literal character. For exam- + ple, {,6} is not a quantifier, but a literal string of four characters. + + In UTF modes, quantifiers apply to characters rather than to individual +- data units. Thus, for example, \x{100}{2} matches two characters, each ++ data units. Thus, for example, \x{100}{2} matches two characters, each + of which is represented by a two-byte sequence in a UTF-8 string. Simi- +- larly, \X{3} matches three Unicode extended grapheme clusters, each of +- which may be several data units long (and they may be of different ++ larly, \X{3} matches three Unicode extended grapheme clusters, each of ++ which may be several data units long (and they may be of different + lengths). + + The quantifier {0} is permitted, causing the expression to behave as if + the previous item and the quantifier were not present. This may be use- +- ful for subpatterns that are referenced as subroutines from elsewhere ++ ful for subpatterns that are referenced as subroutines from elsewhere + in the pattern (but see also the section entitled "Defining subpatterns +- for use by reference only" below). Items other than subpatterns that ++ for use by reference only" below). Items other than subpatterns that + have a {0} quantifier are omitted from the compiled pattern. + +- For convenience, the three most common quantifiers have single-charac- ++ For convenience, the three most common quantifiers have single-charac- + ter abbreviations: + + * is equivalent to {0,} + + is equivalent to {1,} + ? is equivalent to {0,1} + +- It is possible to construct infinite loops by following a subpattern ++ It is possible to construct infinite loops by following a subpattern + that can match no characters with a quantifier that has no upper limit, + for example: + + (a?)* + + Earlier versions of Perl and PCRE used to give an error at compile time +- for such patterns. However, because there are cases where this can be +- useful, such patterns are now accepted, but if any repetition of the +- subpattern does in fact match no characters, the loop is forcibly bro- ++ for such patterns. However, because there are cases where this can be ++ useful, such patterns are now accepted, but if any repetition of the ++ subpattern does in fact match no characters, the loop is forcibly bro- + ken. + +- By default, the quantifiers are "greedy", that is, they match as much +- as possible (up to the maximum number of permitted times), without +- causing the rest of the pattern to fail. The classic example of where ++ By default, the quantifiers are "greedy", that is, they match as much ++ as possible (up to the maximum number of permitted times), without ++ causing the rest of the pattern to fail. The classic example of where + this gives problems is in trying to match comments in C programs. These +- appear between /* and */ and within the comment, individual * and / +- characters may appear. An attempt to match C comments by applying the ++ appear between /* and */ and within the comment, individual * and / ++ characters may appear. An attempt to match C comments by applying the + pattern + + /\*.*\*/ +@@ -6280,19 +6304,19 @@ REPETITION + + /* first comment */ not comment /* second comment */ + +- fails, because it matches the entire string owing to the greediness of ++ fails, because it matches the entire string owing to the greediness of + the .* item. + +- However, if a quantifier is followed by a question mark, it ceases to ++ However, if a quantifier is followed by a question mark, it ceases to + be greedy, and instead matches the minimum number of times possible, so + the pattern + + /\*.*?\*/ + +- does the right thing with the C comments. The meaning of the various +- quantifiers is not otherwise changed, just the preferred number of +- matches. Do not confuse this use of question mark with its use as a +- quantifier in its own right. Because it has two uses, it can sometimes ++ does the right thing with the C comments. The meaning of the various ++ quantifiers is not otherwise changed, just the preferred number of ++ matches. Do not confuse this use of question mark with its use as a ++ quantifier in its own right. Because it has two uses, it can sometimes + appear doubled, as in + + \d??\d +@@ -6300,45 +6324,45 @@ REPETITION + which matches one digit by preference, but can match two if that is the + only way the rest of the pattern matches. + +- If the PCRE_UNGREEDY option is set (an option that is not available in +- Perl), the quantifiers are not greedy by default, but individual ones +- can be made greedy by following them with a question mark. In other ++ If the PCRE_UNGREEDY option is set (an option that is not available in ++ Perl), the quantifiers are not greedy by default, but individual ones ++ can be made greedy by following them with a question mark. In other + words, it inverts the default behaviour. + +- When a parenthesized subpattern is quantified with a minimum repeat +- count that is greater than 1 or with a limited maximum, more memory is +- required for the compiled pattern, in proportion to the size of the ++ When a parenthesized subpattern is quantified with a minimum repeat ++ count that is greater than 1 or with a limited maximum, more memory is ++ required for the compiled pattern, in proportion to the size of the + minimum or maximum. + + If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equiv- +- alent to Perl's /s) is set, thus allowing the dot to match newlines, +- the pattern is implicitly anchored, because whatever follows will be +- tried against every character position in the subject string, so there +- is no point in retrying the overall match at any position after the +- first. PCRE normally treats such a pattern as though it were preceded ++ alent to Perl's /s) is set, thus allowing the dot to match newlines, ++ the pattern is implicitly anchored, because whatever follows will be ++ tried against every character position in the subject string, so there ++ is no point in retrying the overall match at any position after the ++ first. PCRE normally treats such a pattern as though it were preceded + by \A. + +- In cases where it is known that the subject string contains no new- +- lines, it is worth setting PCRE_DOTALL in order to obtain this opti- ++ In cases where it is known that the subject string contains no new- ++ lines, it is worth setting PCRE_DOTALL in order to obtain this opti- + mization, or alternatively using ^ to indicate anchoring explicitly. + +- However, there are some cases where the optimization cannot be used. ++ However, there are some cases where the optimization cannot be used. + When .* is inside capturing parentheses that are the subject of a back + reference elsewhere in the pattern, a match at the start may fail where + a later one succeeds. Consider, for example: + + (.*)abc\1 + +- If the subject is "xyz123abc123" the match point is the fourth charac- ++ If the subject is "xyz123abc123" the match point is the fourth charac- + ter. For this reason, such a pattern is not implicitly anchored. + +- Another case where implicit anchoring is not applied is when the lead- +- ing .* is inside an atomic group. Once again, a match at the start may ++ Another case where implicit anchoring is not applied is when the lead- ++ ing .* is inside an atomic group. Once again, a match at the start may + fail where a later one succeeds. Consider this pattern: + + (?>.*?a)b + +- It matches "ab" in the subject "aab". The use of the backtracking con- ++ It matches "ab" in the subject "aab". The use of the backtracking con- + trol verbs (*PRUNE) and (*SKIP) also disable this optimization. + + When a capturing subpattern is repeated, the value captured is the sub- +@@ -6347,8 +6371,8 @@ REPETITION + (tweedle[dume]{3}\s*)+ + + has matched "tweedledum tweedledee" the value of the captured substring +- is "tweedledee". However, if there are nested capturing subpatterns, +- the corresponding captured values may have been set in previous itera- ++ is "tweedledee". However, if there are nested capturing subpatterns, ++ the corresponding captured values may have been set in previous itera- + tions. For example, after + + /(a|(b))+/ +@@ -6358,53 +6382,53 @@ REPETITION + + ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS + +- With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") +- repetition, failure of what follows normally causes the repeated item +- to be re-evaluated to see if a different number of repeats allows the +- rest of the pattern to match. Sometimes it is useful to prevent this, +- either to change the nature of the match, or to cause it fail earlier +- than it otherwise might, when the author of the pattern knows there is ++ With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") ++ repetition, failure of what follows normally causes the repeated item ++ to be re-evaluated to see if a different number of repeats allows the ++ rest of the pattern to match. Sometimes it is useful to prevent this, ++ either to change the nature of the match, or to cause it fail earlier ++ than it otherwise might, when the author of the pattern knows there is + no point in carrying on. + +- Consider, for example, the pattern \d+foo when applied to the subject ++ Consider, for example, the pattern \d+foo when applied to the subject + line + + 123456bar + + After matching all 6 digits and then failing to match "foo", the normal +- action of the matcher is to try again with only 5 digits matching the +- \d+ item, and then with 4, and so on, before ultimately failing. +- "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides +- the means for specifying that once a subpattern has matched, it is not ++ action of the matcher is to try again with only 5 digits matching the ++ \d+ item, and then with 4, and so on, before ultimately failing. ++ "Atomic grouping" (a term taken from Jeffrey Friedl's book) provides ++ the means for specifying that once a subpattern has matched, it is not + to be re-evaluated in this way. + +- If we use atomic grouping for the previous example, the matcher gives +- up immediately on failing to match "foo" the first time. The notation ++ If we use atomic grouping for the previous example, the matcher gives ++ up immediately on failing to match "foo" the first time. The notation + is a kind of special parenthesis, starting with (?> as in this example: + + (?>\d+)foo + +- This kind of parenthesis "locks up" the part of the pattern it con- +- tains once it has matched, and a failure further into the pattern is +- prevented from backtracking into it. Backtracking past it to previous ++ This kind of parenthesis "locks up" the part of the pattern it con- ++ tains once it has matched, and a failure further into the pattern is ++ prevented from backtracking into it. Backtracking past it to previous + items, however, works as normal. + +- An alternative description is that a subpattern of this type matches +- the string of characters that an identical standalone pattern would ++ An alternative description is that a subpattern of this type matches ++ the string of characters that an identical standalone pattern would + match, if anchored at the current point in the subject string. + + Atomic grouping subpatterns are not capturing subpatterns. Simple cases + such as the above example can be thought of as a maximizing repeat that +- must swallow everything it can. So, while both \d+ and \d+? are pre- +- pared to adjust the number of digits they match in order to make the ++ must swallow everything it can. So, while both \d+ and \d+? are pre- ++ pared to adjust the number of digits they match in order to make the + rest of the pattern match, (?>\d+) can only match an entire sequence of + digits. + +- Atomic groups in general can of course contain arbitrarily complicated +- subpatterns, and can be nested. However, when the subpattern for an ++ Atomic groups in general can of course contain arbitrarily complicated ++ subpatterns, and can be nested. However, when the subpattern for an + atomic group is just a single repeated item, as in the example above, a +- simpler notation, called a "possessive quantifier" can be used. This +- consists of an additional + character following a quantifier. Using ++ simpler notation, called a "possessive quantifier" can be used. This ++ consists of an additional + character following a quantifier. Using + this notation, the previous example can be rewritten as + + \d++foo +@@ -6414,45 +6438,45 @@ ATOMIC GROUPING AND POSSESSIVE QUANTIFIERS + + (abc|xyz){2,3}+ + +- Possessive quantifiers are always greedy; the setting of the ++ Possessive quantifiers are always greedy; the setting of the + PCRE_UNGREEDY option is ignored. They are a convenient notation for the +- simpler forms of atomic group. However, there is no difference in the +- meaning of a possessive quantifier and the equivalent atomic group, +- though there may be a performance difference; possessive quantifiers ++ simpler forms of atomic group. However, there is no difference in the ++ meaning of a possessive quantifier and the equivalent atomic group, ++ though there may be a performance difference; possessive quantifiers + should be slightly faster. + +- The possessive quantifier syntax is an extension to the Perl 5.8 syn- +- tax. Jeffrey Friedl originated the idea (and the name) in the first ++ The possessive quantifier syntax is an extension to the Perl 5.8 syn- ++ tax. Jeffrey Friedl originated the idea (and the name) in the first + edition of his book. Mike McCloskey liked it, so implemented it when he +- built Sun's Java package, and PCRE copied it from there. It ultimately ++ built Sun's Java package, and PCRE copied it from there. It ultimately + found its way into Perl at release 5.10. + + PCRE has an optimization that automatically "possessifies" certain sim- +- ple pattern constructs. For example, the sequence A+B is treated as +- A++B because there is no point in backtracking into a sequence of A's ++ ple pattern constructs. For example, the sequence A+B is treated as ++ A++B because there is no point in backtracking into a sequence of A's + when B must follow. + +- When a pattern contains an unlimited repeat inside a subpattern that +- can itself be repeated an unlimited number of times, the use of an +- atomic group is the only way to avoid some failing matches taking a ++ When a pattern contains an unlimited repeat inside a subpattern that ++ can itself be repeated an unlimited number of times, the use of an ++ atomic group is the only way to avoid some failing matches taking a + very long time indeed. The pattern + + (\D+|<\d+>)*[!?] + +- matches an unlimited number of substrings that either consist of non- +- digits, or digits enclosed in <>, followed by either ! or ?. When it ++ matches an unlimited number of substrings that either consist of non- ++ digits, or digits enclosed in <>, followed by either ! or ?. When it + matches, it runs quickly. However, if it is applied to + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +- it takes a long time before reporting failure. This is because the +- string can be divided between the internal \D+ repeat and the external +- * repeat in a large number of ways, and all have to be tried. (The +- example uses [!?] rather than a single character at the end, because +- both PCRE and Perl have an optimization that allows for fast failure +- when a single character is used. They remember the last single charac- +- ter that is required for a match, and fail early if it is not present +- in the string.) If the pattern is changed so that it uses an atomic ++ it takes a long time before reporting failure. This is because the ++ string can be divided between the internal \D+ repeat and the external ++ * repeat in a large number of ways, and all have to be tried. (The ++ example uses [!?] rather than a single character at the end, because ++ both PCRE and Perl have an optimization that allows for fast failure ++ when a single character is used. They remember the last single charac- ++ ter that is required for a match, and fail early if it is not present ++ in the string.) If the pattern is changed so that it uses an atomic + group, like this: + + ((?>\D+)|<\d+>)*[!?] +@@ -6464,28 +6488,28 @@ BACK REFERENCES + + Outside a character class, a backslash followed by a digit greater than + 0 (and possibly further digits) is a back reference to a capturing sub- +- pattern earlier (that is, to its left) in the pattern, provided there ++ pattern earlier (that is, to its left) in the pattern, provided there + have been that many previous capturing left parentheses. + + However, if the decimal number following the backslash is less than 10, +- it is always taken as a back reference, and causes an error only if +- there are not that many capturing left parentheses in the entire pat- +- tern. In other words, the parentheses that are referenced need not be +- to the left of the reference for numbers less than 10. A "forward back +- reference" of this type can make sense when a repetition is involved +- and the subpattern to the right has participated in an earlier itera- ++ it is always taken as a back reference, and causes an error only if ++ there are not that many capturing left parentheses in the entire pat- ++ tern. In other words, the parentheses that are referenced need not be ++ to the left of the reference for numbers less than 10. A "forward back ++ reference" of this type can make sense when a repetition is involved ++ and the subpattern to the right has participated in an earlier itera- + tion. + +- It is not possible to have a numerical "forward back reference" to a +- subpattern whose number is 10 or more using this syntax because a +- sequence such as \50 is interpreted as a character defined in octal. ++ It is not possible to have a numerical "forward back reference" to a ++ subpattern whose number is 10 or more using this syntax because a ++ sequence such as \50 is interpreted as a character defined in octal. + See the subsection entitled "Non-printing characters" above for further +- details of the handling of digits following a backslash. There is no +- such problem when named parentheses are used. A back reference to any ++ details of the handling of digits following a backslash. There is no ++ such problem when named parentheses are used. A back reference to any + subpattern is possible using named parentheses (see below). + +- Another way of avoiding the ambiguity inherent in the use of digits +- following a backslash is to use the \g escape sequence. This escape ++ Another way of avoiding the ambiguity inherent in the use of digits ++ following a backslash is to use the \g escape sequence. This escape + must be followed by an unsigned number or a negative number, optionally + enclosed in braces. These examples are all identical: + +@@ -6493,7 +6517,7 @@ BACK REFERENCES + (ring), \g1 + (ring), \g{1} + +- An unsigned number specifies an absolute reference without the ambigu- ++ An unsigned number specifies an absolute reference without the ambigu- + ity that is present in the older syntax. It is also useful when literal + digits follow the reference. A negative number is a relative reference. + Consider this example: +@@ -6502,33 +6526,33 @@ BACK REFERENCES + + The sequence \g{-1} is a reference to the most recently started captur- + ing subpattern before \g, that is, is it equivalent to \2 in this exam- +- ple. Similarly, \g{-2} would be equivalent to \1. The use of relative +- references can be helpful in long patterns, and also in patterns that +- are created by joining together fragments that contain references ++ ple. Similarly, \g{-2} would be equivalent to \1. The use of relative ++ references can be helpful in long patterns, and also in patterns that ++ are created by joining together fragments that contain references + within themselves. + +- A back reference matches whatever actually matched the capturing sub- +- pattern in the current subject string, rather than anything matching ++ A back reference matches whatever actually matched the capturing sub- ++ pattern in the current subject string, rather than anything matching + the subpattern itself (see "Subpatterns as subroutines" below for a way + of doing that). So the pattern + + (sens|respons)e and \1ibility + +- matches "sense and sensibility" and "response and responsibility", but +- not "sense and responsibility". If caseful matching is in force at the +- time of the back reference, the case of letters is relevant. For exam- ++ matches "sense and sensibility" and "response and responsibility", but ++ not "sense and responsibility". If caseful matching is in force at the ++ time of the back reference, the case of letters is relevant. For exam- + ple, + + ((?i)rah)\s+\1 + +- matches "rah rah" and "RAH RAH", but not "RAH rah", even though the ++ matches "rah rah" and "RAH RAH", but not "RAH rah", even though the + original capturing subpattern is matched caselessly. + +- There are several different ways of writing back references to named +- subpatterns. The .NET syntax \k{name} and the Perl syntax \k<name> or +- \k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's ++ There are several different ways of writing back references to named ++ subpatterns. The .NET syntax \k{name} and the Perl syntax \k<name> or ++ \k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's + unified back reference syntax, in which \g can be used for both numeric +- and named references, is also supported. We could rewrite the above ++ and named references, is also supported. We could rewrite the above + example in any of the following ways: + + (?<p1>(?i)rah)\s+\k<p1> +@@ -6536,84 +6560,84 @@ BACK REFERENCES + (?P<p1>(?i)rah)\s+(?P=p1) + (?<p1>(?i)rah)\s+\g{p1} + +- A subpattern that is referenced by name may appear in the pattern ++ A subpattern that is referenced by name may appear in the pattern + before or after the reference. + +- There may be more than one back reference to the same subpattern. If a +- subpattern has not actually been used in a particular match, any back ++ There may be more than one back reference to the same subpattern. If a ++ subpattern has not actually been used in a particular match, any back + references to it always fail by default. For example, the pattern + + (a|(bc))\2 + +- always fails if it starts to match "a" rather than "bc". However, if ++ always fails if it starts to match "a" rather than "bc". However, if + the PCRE_JAVASCRIPT_COMPAT option is set at compile time, a back refer- + ence to an unset value matches an empty string. + +- Because there may be many capturing parentheses in a pattern, all dig- +- its following a backslash are taken as part of a potential back refer- +- ence number. If the pattern continues with a digit character, some +- delimiter must be used to terminate the back reference. If the +- PCRE_EXTENDED option is set, this can be white space. Otherwise, the ++ Because there may be many capturing parentheses in a pattern, all dig- ++ its following a backslash are taken as part of a potential back refer- ++ ence number. If the pattern continues with a digit character, some ++ delimiter must be used to terminate the back reference. If the ++ PCRE_EXTENDED option is set, this can be white space. Otherwise, the + \g{ syntax or an empty comment (see "Comments" below) can be used. + + Recursive back references + +- A back reference that occurs inside the parentheses to which it refers +- fails when the subpattern is first used, so, for example, (a\1) never +- matches. However, such references can be useful inside repeated sub- ++ A back reference that occurs inside the parentheses to which it refers ++ fails when the subpattern is first used, so, for example, (a\1) never ++ matches. However, such references can be useful inside repeated sub- + patterns. For example, the pattern + + (a|b\1)+ + + matches any number of "a"s and also "aba", "ababbaa" etc. At each iter- +- ation of the subpattern, the back reference matches the character +- string corresponding to the previous iteration. In order for this to +- work, the pattern must be such that the first iteration does not need +- to match the back reference. This can be done using alternation, as in ++ ation of the subpattern, the back reference matches the character ++ string corresponding to the previous iteration. In order for this to ++ work, the pattern must be such that the first iteration does not need ++ to match the back reference. This can be done using alternation, as in + the example above, or by a quantifier with a minimum of zero. + +- Back references of this type cause the group that they reference to be +- treated as an atomic group. Once the whole group has been matched, a +- subsequent matching failure cannot cause backtracking into the middle ++ Back references of this type cause the group that they reference to be ++ treated as an atomic group. Once the whole group has been matched, a ++ subsequent matching failure cannot cause backtracking into the middle + of the group. + + + ASSERTIONS + +- An assertion is a test on the characters following or preceding the +- current matching point that does not actually consume any characters. +- The simple assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are ++ An assertion is a test on the characters following or preceding the ++ current matching point that does not actually consume any characters. ++ The simple assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are + described above. + +- More complicated assertions are coded as subpatterns. There are two +- kinds: those that look ahead of the current position in the subject +- string, and those that look behind it. An assertion subpattern is +- matched in the normal way, except that it does not cause the current ++ More complicated assertions are coded as subpatterns. There are two ++ kinds: those that look ahead of the current position in the subject ++ string, and those that look behind it. An assertion subpattern is ++ matched in the normal way, except that it does not cause the current + matching position to be changed. + +- Assertion subpatterns are not capturing subpatterns. If such an asser- +- tion contains capturing subpatterns within it, these are counted for +- the purposes of numbering the capturing subpatterns in the whole pat- +- tern. However, substring capturing is carried out only for positive ++ Assertion subpatterns are not capturing subpatterns. If such an asser- ++ tion contains capturing subpatterns within it, these are counted for ++ the purposes of numbering the capturing subpatterns in the whole pat- ++ tern. However, substring capturing is carried out only for positive + assertions. (Perl sometimes, but not always, does do capturing in nega- + tive assertions.) + +- For compatibility with Perl, assertion subpatterns may be repeated; +- though it makes no sense to assert the same thing several times, the +- side effect of capturing parentheses may occasionally be useful. In ++ For compatibility with Perl, assertion subpatterns may be repeated; ++ though it makes no sense to assert the same thing several times, the ++ side effect of capturing parentheses may occasionally be useful. In + practice, there only three cases: + +- (1) If the quantifier is {0}, the assertion is never obeyed during +- matching. However, it may contain internal capturing parenthesized ++ (1) If the quantifier is {0}, the assertion is never obeyed during ++ matching. However, it may contain internal capturing parenthesized + groups that are called from elsewhere via the subroutine mechanism. + +- (2) If quantifier is {0,n} where n is greater than zero, it is treated +- as if it were {0,1}. At run time, the rest of the pattern match is ++ (2) If quantifier is {0,n} where n is greater than zero, it is treated ++ as if it were {0,1}. At run time, the rest of the pattern match is + tried with and without the assertion, the order depending on the greed- + iness of the quantifier. + +- (3) If the minimum repetition is greater than zero, the quantifier is +- ignored. The assertion is obeyed just once when encountered during ++ (3) If the minimum repetition is greater than zero, the quantifier is ++ ignored. The assertion is obeyed just once when encountered during + matching. + + Lookahead assertions +@@ -6623,38 +6647,38 @@ ASSERTIONS + + \w+(?=;) + +- matches a word followed by a semicolon, but does not include the semi- ++ matches a word followed by a semicolon, but does not include the semi- + colon in the match, and + + foo(?!bar) + +- matches any occurrence of "foo" that is not followed by "bar". Note ++ matches any occurrence of "foo" that is not followed by "bar". Note + that the apparently similar pattern + + (?!foo)bar + +- does not find an occurrence of "bar" that is preceded by something +- other than "foo"; it finds any occurrence of "bar" whatsoever, because ++ does not find an occurrence of "bar" that is preceded by something ++ other than "foo"; it finds any occurrence of "bar" whatsoever, because + the assertion (?!foo) is always true when the next three characters are + "bar". A lookbehind assertion is needed to achieve the other effect. + + If you want to force a matching failure at some point in a pattern, the +- most convenient way to do it is with (?!) because an empty string +- always matches, so an assertion that requires there not to be an empty ++ most convenient way to do it is with (?!) because an empty string ++ always matches, so an assertion that requires there not to be an empty + string must always fail. The backtracking control verb (*FAIL) or (*F) + is a synonym for (?!). + + Lookbehind assertions + +- Lookbehind assertions start with (?<= for positive assertions and (?<! ++ Lookbehind assertions start with (?<= for positive assertions and (?<! + for negative assertions. For example, + + (?<!foo)bar + +- does find an occurrence of "bar" that is not preceded by "foo". The +- contents of a lookbehind assertion are restricted such that all the ++ does find an occurrence of "bar" that is not preceded by "foo". The ++ contents of a lookbehind assertion are restricted such that all the + strings it matches must have a fixed length. However, if there are sev- +- eral top-level alternatives, they do not all have to have the same ++ eral top-level alternatives, they do not all have to have the same + fixed length. Thus + + (?<=bullock|donkey) +@@ -6663,62 +6687,62 @@ ASSERTIONS + + (?<!dogs?|cats?) + +- causes an error at compile time. Branches that match different length +- strings are permitted only at the top level of a lookbehind assertion. ++ causes an error at compile time. Branches that match different length ++ strings are permitted only at the top level of a lookbehind assertion. + This is an extension compared with Perl, which requires all branches to + match the same length of string. An assertion such as + + (?<=ab(c|de)) + +- is not permitted, because its single top-level branch can match two ++ is not permitted, because its single top-level branch can match two + different lengths, but it is acceptable to PCRE if rewritten to use two + top-level branches: + + (?<=abc|abde) + +- In some cases, the escape sequence \K (see above) can be used instead ++ In some cases, the escape sequence \K (see above) can be used instead + of a lookbehind assertion to get round the fixed-length restriction. + +- The implementation of lookbehind assertions is, for each alternative, +- to temporarily move the current position back by the fixed length and ++ The implementation of lookbehind assertions is, for each alternative, ++ to temporarily move the current position back by the fixed length and + then try to match. If there are insufficient characters before the cur- + rent position, the assertion fails. + +- In a UTF mode, PCRE does not allow the \C escape (which matches a sin- +- gle data unit even in a UTF mode) to appear in lookbehind assertions, +- because it makes it impossible to calculate the length of the lookbe- +- hind. The \X and \R escapes, which can match different numbers of data ++ In a UTF mode, PCRE does not allow the \C escape (which matches a sin- ++ gle data unit even in a UTF mode) to appear in lookbehind assertions, ++ because it makes it impossible to calculate the length of the lookbe- ++ hind. The \X and \R escapes, which can match different numbers of data + units, are also not permitted. + +- "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in +- lookbehinds, as long as the subpattern matches a fixed-length string. ++ "Subroutine" calls (see below) such as (?2) or (?&X) are permitted in ++ lookbehinds, as long as the subpattern matches a fixed-length string. + Recursion, however, is not supported. + +- Possessive quantifiers can be used in conjunction with lookbehind ++ Possessive quantifiers can be used in conjunction with lookbehind + assertions to specify efficient matching of fixed-length strings at the + end of subject strings. Consider a simple pattern such as + + abcd$ + +- when applied to a long string that does not match. Because matching ++ when applied to a long string that does not match. Because matching + proceeds from left to right, PCRE will look for each "a" in the subject +- and then see if what follows matches the rest of the pattern. If the ++ and then see if what follows matches the rest of the pattern. If the + pattern is specified as + + ^.*abcd$ + +- the initial .* matches the entire string at first, but when this fails ++ the initial .* matches the entire string at first, but when this fails + (because there is no following "a"), it backtracks to match all but the +- last character, then all but the last two characters, and so on. Once +- again the search for "a" covers the entire string, from right to left, ++ last character, then all but the last two characters, and so on. Once ++ again the search for "a" covers the entire string, from right to left, + so we are no better off. However, if the pattern is written as + + ^.*+(?<=abcd) + +- there can be no backtracking for the .*+ item; it can match only the +- entire string. The subsequent lookbehind assertion does a single test +- on the last four characters. If it fails, the match fails immediately. +- For long strings, this approach makes a significant difference to the ++ there can be no backtracking for the .*+ item; it can match only the ++ entire string. The subsequent lookbehind assertion does a single test ++ on the last four characters. If it fails, the match fails immediately. ++ For long strings, this approach makes a significant difference to the + processing time. + + Using multiple assertions +@@ -6727,18 +6751,18 @@ ASSERTIONS + + (?<=\d{3})(?<!999)foo + +- matches "foo" preceded by three digits that are not "999". Notice that +- each of the assertions is applied independently at the same point in +- the subject string. First there is a check that the previous three +- characters are all digits, and then there is a check that the same ++ matches "foo" preceded by three digits that are not "999". Notice that ++ each of the assertions is applied independently at the same point in ++ the subject string. First there is a check that the previous three ++ characters are all digits, and then there is a check that the same + three characters are not "999". This pattern does not match "foo" pre- +- ceded by six characters, the first of which are digits and the last +- three of which are not "999". For example, it doesn't match "123abc- ++ ceded by six characters, the first of which are digits and the last ++ three of which are not "999". For example, it doesn't match "123abc- + foo". A pattern to do that is + + (?<=\d{3}...)(?<!999)foo + +- This time the first assertion looks at the preceding six characters, ++ This time the first assertion looks at the preceding six characters, + checking that the first three are digits, and then the second assertion + checks that the preceding three characters are not "999". + +@@ -6746,29 +6770,29 @@ ASSERTIONS + + (?<=(?<!foo)bar)baz + +- matches an occurrence of "baz" that is preceded by "bar" which in turn ++ matches an occurrence of "baz" that is preceded by "bar" which in turn + is not preceded by "foo", while + + (?<=\d{3}(?!999)...)foo + +- is another pattern that matches "foo" preceded by three digits and any ++ is another pattern that matches "foo" preceded by three digits and any + three characters that are not "999". + + + CONDITIONAL SUBPATTERNS + +- It is possible to cause the matching process to obey a subpattern con- +- ditionally or to choose between two alternative subpatterns, depending +- on the result of an assertion, or whether a specific capturing subpat- +- tern has already been matched. The two possible forms of conditional ++ It is possible to cause the matching process to obey a subpattern con- ++ ditionally or to choose between two alternative subpatterns, depending ++ on the result of an assertion, or whether a specific capturing subpat- ++ tern has already been matched. The two possible forms of conditional + subpattern are: + + (?(condition)yes-pattern) + (?(condition)yes-pattern|no-pattern) + +- If the condition is satisfied, the yes-pattern is used; otherwise the +- no-pattern (if present) is used. If there are more than two alterna- +- tives in the subpattern, a compile-time error occurs. Each of the two ++ If the condition is satisfied, the yes-pattern is used; otherwise the ++ no-pattern (if present) is used. If there are more than two alterna- ++ tives in the subpattern, a compile-time error occurs. Each of the two + alternatives may itself contain nested subpatterns of any form, includ- + ing conditional subpatterns; the restriction to two alternatives + applies only at the level of the condition. This pattern fragment is an +@@ -6777,68 +6801,68 @@ CONDITIONAL SUBPATTERNS + (?(1) (A|B|C) | (D | (?(2)E|F) | E) ) + + +- There are four kinds of condition: references to subpatterns, refer- ++ There are four kinds of condition: references to subpatterns, refer- + ences to recursion, a pseudo-condition called DEFINE, and assertions. + + Checking for a used subpattern by number + +- If the text between the parentheses consists of a sequence of digits, ++ If the text between the parentheses consists of a sequence of digits, + the condition is true if a capturing subpattern of that number has pre- +- viously matched. If there is more than one capturing subpattern with +- the same number (see the earlier section about duplicate subpattern +- numbers), the condition is true if any of them have matched. An alter- +- native notation is to precede the digits with a plus or minus sign. In +- this case, the subpattern number is relative rather than absolute. The +- most recently opened parentheses can be referenced by (?(-1), the next +- most recent by (?(-2), and so on. Inside loops it can also make sense ++ viously matched. If there is more than one capturing subpattern with ++ the same number (see the earlier section about duplicate subpattern ++ numbers), the condition is true if any of them have matched. An alter- ++ native notation is to precede the digits with a plus or minus sign. In ++ this case, the subpattern number is relative rather than absolute. The ++ most recently opened parentheses can be referenced by (?(-1), the next ++ most recent by (?(-2), and so on. Inside loops it can also make sense + to refer to subsequent groups. The next parentheses to be opened can be +- referenced as (?(+1), and so on. (The value zero in any of these forms ++ referenced as (?(+1), and so on. (The value zero in any of these forms + is not used; it provokes a compile-time error.) + +- Consider the following pattern, which contains non-significant white ++ Consider the following pattern, which contains non-significant white + space to make it more readable (assume the PCRE_EXTENDED option) and to + divide it into three parts for ease of discussion: + + ( \( )? [^()]+ (?(1) \) ) + +- The first part matches an optional opening parenthesis, and if that ++ The first part matches an optional opening parenthesis, and if that + character is present, sets it as the first captured substring. The sec- +- ond part matches one or more characters that are not parentheses. The +- third part is a conditional subpattern that tests whether or not the +- first set of parentheses matched. If they did, that is, if subject +- started with an opening parenthesis, the condition is true, and so the +- yes-pattern is executed and a closing parenthesis is required. Other- +- wise, since no-pattern is not present, the subpattern matches nothing. +- In other words, this pattern matches a sequence of non-parentheses, ++ ond part matches one or more characters that are not parentheses. The ++ third part is a conditional subpattern that tests whether or not the ++ first set of parentheses matched. If they did, that is, if subject ++ started with an opening parenthesis, the condition is true, and so the ++ yes-pattern is executed and a closing parenthesis is required. Other- ++ wise, since no-pattern is not present, the subpattern matches nothing. ++ In other words, this pattern matches a sequence of non-parentheses, + optionally enclosed in parentheses. + +- If you were embedding this pattern in a larger one, you could use a ++ If you were embedding this pattern in a larger one, you could use a + relative reference: + + ...other stuff... ( \( )? [^()]+ (?(-1) \) ) ... + +- This makes the fragment independent of the parentheses in the larger ++ This makes the fragment independent of the parentheses in the larger + pattern. + + Checking for a used subpattern by name + +- Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a +- used subpattern by name. For compatibility with earlier versions of +- PCRE, which had this facility before Perl, the syntax (?(name)...) is ++ Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a ++ used subpattern by name. For compatibility with earlier versions of ++ PCRE, which had this facility before Perl, the syntax (?(name)...) is + also recognized. + + Rewriting the above example to use a named subpattern gives this: + + (?<OPEN> \( )? [^()]+ (?(<OPEN>) \) ) + +- If the name used in a condition of this kind is a duplicate, the test +- is applied to all subpatterns of the same name, and is true if any one ++ If the name used in a condition of this kind is a duplicate, the test ++ is applied to all subpatterns of the same name, and is true if any one + of them has matched. + + Checking for pattern recursion + + If the condition is the string (R), and there is no subpattern with the +- name R, the condition is true if a recursive call to the whole pattern ++ name R, the condition is true if a recursive call to the whole pattern + or any subpattern has been made. If digits or a name preceded by amper- + sand follow the letter R, for example: + +@@ -6846,51 +6870,51 @@ CONDITIONAL SUBPATTERNS + + the condition is true if the most recent recursion is into a subpattern + whose number or name is given. This condition does not check the entire +- recursion stack. If the name used in a condition of this kind is a ++ recursion stack. If the name used in a condition of this kind is a + duplicate, the test is applied to all subpatterns of the same name, and + is true if any one of them is the most recent recursion. + +- At "top level", all these recursion test conditions are false. The ++ At "top level", all these recursion test conditions are false. The + syntax for recursive patterns is described below. + + Defining subpatterns for use by reference only + +- If the condition is the string (DEFINE), and there is no subpattern +- with the name DEFINE, the condition is always false. In this case, +- there may be only one alternative in the subpattern. It is always +- skipped if control reaches this point in the pattern; the idea of +- DEFINE is that it can be used to define subroutines that can be refer- +- enced from elsewhere. (The use of subroutines is described below.) For +- example, a pattern to match an IPv4 address such as "192.168.23.245" ++ If the condition is the string (DEFINE), and there is no subpattern ++ with the name DEFINE, the condition is always false. In this case, ++ there may be only one alternative in the subpattern. It is always ++ skipped if control reaches this point in the pattern; the idea of ++ DEFINE is that it can be used to define subroutines that can be refer- ++ enced from elsewhere. (The use of subroutines is described below.) For ++ example, a pattern to match an IPv4 address such as "192.168.23.245" + could be written like this (ignore white space and line breaks): + + (?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) ) + \b (?&byte) (\.(?&byte)){3} \b + +- The first part of the pattern is a DEFINE group inside which a another +- group named "byte" is defined. This matches an individual component of +- an IPv4 address (a number less than 256). When matching takes place, +- this part of the pattern is skipped because DEFINE acts like a false +- condition. The rest of the pattern uses references to the named group +- to match the four dot-separated components of an IPv4 address, insist- ++ The first part of the pattern is a DEFINE group inside which a another ++ group named "byte" is defined. This matches an individual component of ++ an IPv4 address (a number less than 256). When matching takes place, ++ this part of the pattern is skipped because DEFINE acts like a false ++ condition. The rest of the pattern uses references to the named group ++ to match the four dot-separated components of an IPv4 address, insist- + ing on a word boundary at each end. + + Assertion conditions + +- If the condition is not in any of the above formats, it must be an +- assertion. This may be a positive or negative lookahead or lookbehind +- assertion. Consider this pattern, again containing non-significant ++ If the condition is not in any of the above formats, it must be an ++ assertion. This may be a positive or negative lookahead or lookbehind ++ assertion. Consider this pattern, again containing non-significant + white space, and with the two alternatives on the second line: + + (?(?=[^a-z]*[a-z]) + \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) + +- The condition is a positive lookahead assertion that matches an +- optional sequence of non-letters followed by a letter. In other words, +- it tests for the presence of at least one letter in the subject. If a +- letter is found, the subject is matched against the first alternative; +- otherwise it is matched against the second. This pattern matches +- strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are ++ The condition is a positive lookahead assertion that matches an ++ optional sequence of non-letters followed by a letter. In other words, ++ it tests for the presence of at least one letter in the subject. If a ++ letter is found, the subject is matched against the first alternative; ++ otherwise it is matched against the second. This pattern matches ++ strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are + letters and dd are digits. + + +@@ -6899,41 +6923,41 @@ COMMENTS + There are two ways of including comments in patterns that are processed + by PCRE. In both cases, the start of the comment must not be in a char- + acter class, nor in the middle of any other sequence of related charac- +- ters such as (?: or a subpattern name or number. The characters that ++ ters such as (?: or a subpattern name or number. The characters that + make up a comment play no part in the pattern matching. + +- The sequence (?# marks the start of a comment that continues up to the +- next closing parenthesis. Nested parentheses are not permitted. If the ++ The sequence (?# marks the start of a comment that continues up to the ++ next closing parenthesis. Nested parentheses are not permitted. If the + PCRE_EXTENDED option is set, an unescaped # character also introduces a +- comment, which in this case continues to immediately after the next +- newline character or character sequence in the pattern. Which charac- ++ comment, which in this case continues to immediately after the next ++ newline character or character sequence in the pattern. Which charac- + ters are interpreted as newlines is controlled by the options passed to +- a compiling function or by a special sequence at the start of the pat- ++ a compiling function or by a special sequence at the start of the pat- + tern, as described in the section entitled "Newline conventions" above. + Note that the end of this type of comment is a literal newline sequence +- in the pattern; escape sequences that happen to represent a newline do +- not count. For example, consider this pattern when PCRE_EXTENDED is ++ in the pattern; escape sequences that happen to represent a newline do ++ not count. For example, consider this pattern when PCRE_EXTENDED is + set, and the default newline convention is in force: + + abc #comment \n still comment + +- On encountering the # character, pcre_compile() skips along, looking +- for a newline in the pattern. The sequence \n is still literal at this +- stage, so it does not terminate the comment. Only an actual character ++ On encountering the # character, pcre_compile() skips along, looking ++ for a newline in the pattern. The sequence \n is still literal at this ++ stage, so it does not terminate the comment. Only an actual character + with the code value 0x0a (the default newline) does so. + + + RECURSIVE PATTERNS + +- Consider the problem of matching a string in parentheses, allowing for +- unlimited nested parentheses. Without the use of recursion, the best +- that can be done is to use a pattern that matches up to some fixed +- depth of nesting. It is not possible to handle an arbitrary nesting ++ Consider the problem of matching a string in parentheses, allowing for ++ unlimited nested parentheses. Without the use of recursion, the best ++ that can be done is to use a pattern that matches up to some fixed ++ depth of nesting. It is not possible to handle an arbitrary nesting + depth. + + For some time, Perl has provided a facility that allows regular expres- +- sions to recurse (amongst other things). It does this by interpolating +- Perl code in the expression at run time, and the code can refer to the ++ sions to recurse (amongst other things). It does this by interpolating ++ Perl code in the expression at run time, and the code can refer to the + expression itself. A Perl pattern using code interpolation to solve the + parentheses problem can be created like this: + +@@ -6943,201 +6967,201 @@ RECURSIVE PATTERNS + refers recursively to the pattern in which it appears. + + Obviously, PCRE cannot support the interpolation of Perl code. Instead, +- it supports special syntax for recursion of the entire pattern, and +- also for individual subpattern recursion. After its introduction in +- PCRE and Python, this kind of recursion was subsequently introduced ++ it supports special syntax for recursion of the entire pattern, and ++ also for individual subpattern recursion. After its introduction in ++ PCRE and Python, this kind of recursion was subsequently introduced + into Perl at release 5.10. + +- A special item that consists of (? followed by a number greater than +- zero and a closing parenthesis is a recursive subroutine call of the +- subpattern of the given number, provided that it occurs inside that +- subpattern. (If not, it is a non-recursive subroutine call, which is +- described in the next section.) The special item (?R) or (?0) is a ++ A special item that consists of (? followed by a number greater than ++ zero and a closing parenthesis is a recursive subroutine call of the ++ subpattern of the given number, provided that it occurs inside that ++ subpattern. (If not, it is a non-recursive subroutine call, which is ++ described in the next section.) The special item (?R) or (?0) is a + recursive call of the entire regular expression. + +- This PCRE pattern solves the nested parentheses problem (assume the ++ This PCRE pattern solves the nested parentheses problem (assume the + PCRE_EXTENDED option is set so that white space is ignored): + + \( ( [^()]++ | (?R) )* \) + +- First it matches an opening parenthesis. Then it matches any number of +- substrings which can either be a sequence of non-parentheses, or a +- recursive match of the pattern itself (that is, a correctly parenthe- ++ First it matches an opening parenthesis. Then it matches any number of ++ substrings which can either be a sequence of non-parentheses, or a ++ recursive match of the pattern itself (that is, a correctly parenthe- + sized substring). Finally there is a closing parenthesis. Note the use + of a possessive quantifier to avoid backtracking into sequences of non- + parentheses. + +- If this were part of a larger pattern, you would not want to recurse ++ If this were part of a larger pattern, you would not want to recurse + the entire pattern, so instead you could use this: + + ( \( ( [^()]++ | (?1) )* \) ) + +- We have put the pattern into parentheses, and caused the recursion to ++ We have put the pattern into parentheses, and caused the recursion to + refer to them instead of the whole pattern. + +- In a larger pattern, keeping track of parenthesis numbers can be +- tricky. This is made easier by the use of relative references. Instead ++ In a larger pattern, keeping track of parenthesis numbers can be ++ tricky. This is made easier by the use of relative references. Instead + of (?1) in the pattern above you can write (?-2) to refer to the second +- most recently opened parentheses preceding the recursion. In other +- words, a negative number counts capturing parentheses leftwards from ++ most recently opened parentheses preceding the recursion. In other ++ words, a negative number counts capturing parentheses leftwards from + the point at which it is encountered. + +- It is also possible to refer to subsequently opened parentheses, by +- writing references such as (?+2). However, these cannot be recursive +- because the reference is not inside the parentheses that are refer- +- enced. They are always non-recursive subroutine calls, as described in ++ It is also possible to refer to subsequently opened parentheses, by ++ writing references such as (?+2). However, these cannot be recursive ++ because the reference is not inside the parentheses that are refer- ++ enced. They are always non-recursive subroutine calls, as described in + the next section. + +- An alternative approach is to use named parentheses instead. The Perl +- syntax for this is (?&name); PCRE's earlier syntax (?P>name) is also ++ An alternative approach is to use named parentheses instead. The Perl ++ syntax for this is (?&name); PCRE's earlier syntax (?P>name) is also + supported. We could rewrite the above example as follows: + + (?<pn> \( ( [^()]++ | (?&pn) )* \) ) + +- If there is more than one subpattern with the same name, the earliest ++ If there is more than one subpattern with the same name, the earliest + one is used. + +- This particular example pattern that we have been looking at contains ++ This particular example pattern that we have been looking at contains + nested unlimited repeats, and so the use of a possessive quantifier for + matching strings of non-parentheses is important when applying the pat- +- tern to strings that do not match. For example, when this pattern is ++ tern to strings that do not match. For example, when this pattern is + applied to + + (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() + +- it yields "no match" quickly. However, if a possessive quantifier is +- not used, the match runs for a very long time indeed because there are +- so many different ways the + and * repeats can carve up the subject, ++ it yields "no match" quickly. However, if a possessive quantifier is ++ not used, the match runs for a very long time indeed because there are ++ so many different ways the + and * repeats can carve up the subject, + and all have to be tested before failure can be reported. + +- At the end of a match, the values of capturing parentheses are those +- from the outermost level. If you want to obtain intermediate values, a +- callout function can be used (see below and the pcrecallout documenta- ++ At the end of a match, the values of capturing parentheses are those ++ from the outermost level. If you want to obtain intermediate values, a ++ callout function can be used (see below and the pcrecallout documenta- + tion). If the pattern above is matched against + + (ab(cd)ef) + +- the value for the inner capturing parentheses (numbered 2) is "ef", +- which is the last value taken on at the top level. If a capturing sub- +- pattern is not matched at the top level, its final captured value is +- unset, even if it was (temporarily) set at a deeper level during the ++ the value for the inner capturing parentheses (numbered 2) is "ef", ++ which is the last value taken on at the top level. If a capturing sub- ++ pattern is not matched at the top level, its final captured value is ++ unset, even if it was (temporarily) set at a deeper level during the + matching process. + +- If there are more than 15 capturing parentheses in a pattern, PCRE has +- to obtain extra memory to store data during a recursion, which it does ++ If there are more than 15 capturing parentheses in a pattern, PCRE has ++ to obtain extra memory to store data during a recursion, which it does + by using pcre_malloc, freeing it via pcre_free afterwards. If no memory + can be obtained, the match fails with the PCRE_ERROR_NOMEMORY error. + +- Do not confuse the (?R) item with the condition (R), which tests for +- recursion. Consider this pattern, which matches text in angle brack- +- ets, allowing for arbitrary nesting. Only digits are allowed in nested +- brackets (that is, when recursing), whereas any characters are permit- ++ Do not confuse the (?R) item with the condition (R), which tests for ++ recursion. Consider this pattern, which matches text in angle brack- ++ ets, allowing for arbitrary nesting. Only digits are allowed in nested ++ brackets (that is, when recursing), whereas any characters are permit- + ted at the outer level. + + < (?: (?(R) \d++ | [^<>]*+) | (?R)) * > + +- In this pattern, (?(R) is the start of a conditional subpattern, with +- two different alternatives for the recursive and non-recursive cases. ++ In this pattern, (?(R) is the start of a conditional subpattern, with ++ two different alternatives for the recursive and non-recursive cases. + The (?R) item is the actual recursive call. + + Differences in recursion processing between PCRE and Perl + +- Recursion processing in PCRE differs from Perl in two important ways. +- In PCRE (like Python, but unlike Perl), a recursive subpattern call is ++ Recursion processing in PCRE differs from Perl in two important ways. ++ In PCRE (like Python, but unlike Perl), a recursive subpattern call is + always treated as an atomic group. That is, once it has matched some of + the subject string, it is never re-entered, even if it contains untried +- alternatives and there is a subsequent matching failure. This can be +- illustrated by the following pattern, which purports to match a palin- +- dromic string that contains an odd number of characters (for example, ++ alternatives and there is a subsequent matching failure. This can be ++ illustrated by the following pattern, which purports to match a palin- ++ dromic string that contains an odd number of characters (for example, + "a", "aba", "abcba", "abcdcba"): + + ^(.|(.)(?1)\2)$ + + The idea is that it either matches a single character, or two identical +- characters surrounding a sub-palindrome. In Perl, this pattern works; +- in PCRE it does not if the pattern is longer than three characters. ++ characters surrounding a sub-palindrome. In Perl, this pattern works; ++ in PCRE it does not if the pattern is longer than three characters. + Consider the subject string "abcba": + +- At the top level, the first character is matched, but as it is not at ++ At the top level, the first character is matched, but as it is not at + the end of the string, the first alternative fails; the second alterna- + tive is taken and the recursion kicks in. The recursive call to subpat- +- tern 1 successfully matches the next character ("b"). (Note that the ++ tern 1 successfully matches the next character ("b"). (Note that the + beginning and end of line tests are not part of the recursion). + +- Back at the top level, the next character ("c") is compared with what +- subpattern 2 matched, which was "a". This fails. Because the recursion +- is treated as an atomic group, there are now no backtracking points, +- and so the entire match fails. (Perl is able, at this point, to re- +- enter the recursion and try the second alternative.) However, if the ++ Back at the top level, the next character ("c") is compared with what ++ subpattern 2 matched, which was "a". This fails. Because the recursion ++ is treated as an atomic group, there are now no backtracking points, ++ and so the entire match fails. (Perl is able, at this point, to re- ++ enter the recursion and try the second alternative.) However, if the + pattern is written with the alternatives in the other order, things are + different: + + ^((.)(?1)\2|.)$ + +- This time, the recursing alternative is tried first, and continues to +- recurse until it runs out of characters, at which point the recursion +- fails. But this time we do have another alternative to try at the +- higher level. That is the big difference: in the previous case the ++ This time, the recursing alternative is tried first, and continues to ++ recurse until it runs out of characters, at which point the recursion ++ fails. But this time we do have another alternative to try at the ++ higher level. That is the big difference: in the previous case the + remaining alternative is at a deeper recursion level, which PCRE cannot + use. + +- To change the pattern so that it matches all palindromic strings, not +- just those with an odd number of characters, it is tempting to change ++ To change the pattern so that it matches all palindromic strings, not ++ just those with an odd number of characters, it is tempting to change + the pattern to this: + + ^((.)(?1)\2|.?)$ + +- Again, this works in Perl, but not in PCRE, and for the same reason. +- When a deeper recursion has matched a single character, it cannot be +- entered again in order to match an empty string. The solution is to +- separate the two cases, and write out the odd and even cases as alter- ++ Again, this works in Perl, but not in PCRE, and for the same reason. ++ When a deeper recursion has matched a single character, it cannot be ++ entered again in order to match an empty string. The solution is to ++ separate the two cases, and write out the odd and even cases as alter- + natives at the higher level: + + ^(?:((.)(?1)\2|)|((.)(?3)\4|.)) + +- If you want to match typical palindromic phrases, the pattern has to ++ If you want to match typical palindromic phrases, the pattern has to + ignore all non-word characters, which can be done like this: + + ^\W*+(?:((.)\W*+(?1)\W*+\2|)|((.)\W*+(?3)\W*+\4|\W*+.\W*+))\W*+$ + + If run with the PCRE_CASELESS option, this pattern matches phrases such + as "A man, a plan, a canal: Panama!" and it works well in both PCRE and +- Perl. Note the use of the possessive quantifier *+ to avoid backtrack- +- ing into sequences of non-word characters. Without this, PCRE takes a +- great deal longer (ten times or more) to match typical phrases, and ++ Perl. Note the use of the possessive quantifier *+ to avoid backtrack- ++ ing into sequences of non-word characters. Without this, PCRE takes a ++ great deal longer (ten times or more) to match typical phrases, and + Perl takes so long that you think it has gone into a loop. + +- WARNING: The palindrome-matching patterns above work only if the sub- +- ject string does not start with a palindrome that is shorter than the +- entire string. For example, although "abcba" is correctly matched, if +- the subject is "ababa", PCRE finds the palindrome "aba" at the start, +- then fails at top level because the end of the string does not follow. +- Once again, it cannot jump back into the recursion to try other alter- ++ WARNING: The palindrome-matching patterns above work only if the sub- ++ ject string does not start with a palindrome that is shorter than the ++ entire string. For example, although "abcba" is correctly matched, if ++ the subject is "ababa", PCRE finds the palindrome "aba" at the start, ++ then fails at top level because the end of the string does not follow. ++ Once again, it cannot jump back into the recursion to try other alter- + natives, so the entire match fails. + +- The second way in which PCRE and Perl differ in their recursion pro- +- cessing is in the handling of captured values. In Perl, when a subpat- +- tern is called recursively or as a subpattern (see the next section), +- it has no access to any values that were captured outside the recur- +- sion, whereas in PCRE these values can be referenced. Consider this ++ The second way in which PCRE and Perl differ in their recursion pro- ++ cessing is in the handling of captured values. In Perl, when a subpat- ++ tern is called recursively or as a subpattern (see the next section), ++ it has no access to any values that were captured outside the recur- ++ sion, whereas in PCRE these values can be referenced. Consider this + pattern: + + ^(.)(\1|a(?2)) + +- In PCRE, this pattern matches "bab". The first capturing parentheses +- match "b", then in the second group, when the back reference \1 fails +- to match "b", the second alternative matches "a" and then recurses. In +- the recursion, \1 does now match "b" and so the whole match succeeds. +- In Perl, the pattern fails to match because inside the recursive call ++ In PCRE, this pattern matches "bab". The first capturing parentheses ++ match "b", then in the second group, when the back reference \1 fails ++ to match "b", the second alternative matches "a" and then recurses. In ++ the recursion, \1 does now match "b" and so the whole match succeeds. ++ In Perl, the pattern fails to match because inside the recursive call + \1 cannot access the externally set value. + + + SUBPATTERNS AS SUBROUTINES + +- If the syntax for a recursive subpattern call (either by number or by +- name) is used outside the parentheses to which it refers, it operates +- like a subroutine in a programming language. The called subpattern may +- be defined before or after the reference. A numbered reference can be ++ If the syntax for a recursive subpattern call (either by number or by ++ name) is used outside the parentheses to which it refers, it operates ++ like a subroutine in a programming language. The called subpattern may ++ be defined before or after the reference. A numbered reference can be + absolute or relative, as in these examples: + + (...(absolute)...)...(?2)... +@@ -7148,79 +7172,79 @@ SUBPATTERNS AS SUBROUTINES + + (sens|respons)e and \1ibility + +- matches "sense and sensibility" and "response and responsibility", but ++ matches "sense and sensibility" and "response and responsibility", but + not "sense and responsibility". If instead the pattern + + (sens|respons)e and (?1)ibility + +- is used, it does match "sense and responsibility" as well as the other +- two strings. Another example is given in the discussion of DEFINE ++ is used, it does match "sense and responsibility" as well as the other ++ two strings. Another example is given in the discussion of DEFINE + above. + +- All subroutine calls, whether recursive or not, are always treated as +- atomic groups. That is, once a subroutine has matched some of the sub- ++ All subroutine calls, whether recursive or not, are always treated as ++ atomic groups. That is, once a subroutine has matched some of the sub- + ject string, it is never re-entered, even if it contains untried alter- +- natives and there is a subsequent matching failure. Any capturing +- parentheses that are set during the subroutine call revert to their ++ natives and there is a subsequent matching failure. Any capturing ++ parentheses that are set during the subroutine call revert to their + previous values afterwards. + +- Processing options such as case-independence are fixed when a subpat- +- tern is defined, so if it is used as a subroutine, such options cannot ++ Processing options such as case-independence are fixed when a subpat- ++ tern is defined, so if it is used as a subroutine, such options cannot + be changed for different calls. For example, consider this pattern: + + (abc)(?i:(?-1)) + +- It matches "abcabc". It does not match "abcABC" because the change of ++ It matches "abcabc". It does not match "abcABC" because the change of + processing option does not affect the called subpattern. + + + ONIGURUMA SUBROUTINE SYNTAX + +- For compatibility with Oniguruma, the non-Perl syntax \g followed by a ++ For compatibility with Oniguruma, the non-Perl syntax \g followed by a + name or a number enclosed either in angle brackets or single quotes, is +- an alternative syntax for referencing a subpattern as a subroutine, +- possibly recursively. Here are two of the examples used above, rewrit- ++ an alternative syntax for referencing a subpattern as a subroutine, ++ possibly recursively. Here are two of the examples used above, rewrit- + ten using this syntax: + + (?<pn> \( ( (?>[^()]+) | \g<pn> )* \) ) + (sens|respons)e and \g'1'ibility + +- PCRE supports an extension to Oniguruma: if a number is preceded by a ++ PCRE supports an extension to Oniguruma: if a number is preceded by a + plus or a minus sign it is taken as a relative reference. For example: + + (abc)(?i:\g<-1>) + +- Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not +- synonymous. The former is a back reference; the latter is a subroutine ++ Note that \g{...} (Perl syntax) and \g<...> (Oniguruma syntax) are not ++ synonymous. The former is a back reference; the latter is a subroutine + call. + + + CALLOUTS + + Perl has a feature whereby using the sequence (?{...}) causes arbitrary +- Perl code to be obeyed in the middle of matching a regular expression. ++ Perl code to be obeyed in the middle of matching a regular expression. + This makes it possible, amongst other things, to extract different sub- + strings that match the same pair of parentheses when there is a repeti- + tion. + + PCRE provides a similar feature, but of course it cannot obey arbitrary + Perl code. The feature is called "callout". The caller of PCRE provides +- an external function by putting its entry point in the global variable +- pcre_callout (8-bit library) or pcre[16|32]_callout (16-bit or 32-bit +- library). By default, this variable contains NULL, which disables all ++ an external function by putting its entry point in the global variable ++ pcre_callout (8-bit library) or pcre[16|32]_callout (16-bit or 32-bit ++ library). By default, this variable contains NULL, which disables all + calling out. + +- Within a regular expression, (?C) indicates the points at which the +- external function is to be called. If you want to identify different +- callout points, you can put a number less than 256 after the letter C. +- The default value is zero. For example, this pattern has two callout ++ Within a regular expression, (?C) indicates the points at which the ++ external function is to be called. If you want to identify different ++ callout points, you can put a number less than 256 after the letter C. ++ The default value is zero. For example, this pattern has two callout + points: + + (?C1)abc(?C2)def + +- If the PCRE_AUTO_CALLOUT flag is passed to a compiling function, call- +- outs are automatically installed before each item in the pattern. They +- are all numbered 255. If there is a conditional group in the pattern ++ If the PCRE_AUTO_CALLOUT flag is passed to a compiling function, call- ++ outs are automatically installed before each item in the pattern. They ++ are all numbered 255. If there is a conditional group in the pattern + whose condition is an assertion, an additional callout is inserted just + before the condition. An explicit callout may also be set at this posi- + tion, as in this example: +@@ -7230,120 +7254,120 @@ CALLOUTS + Note that this applies only to assertion conditions, not to other types + of condition. + +- During matching, when PCRE reaches a callout point, the external func- +- tion is called. It is provided with the number of the callout, the +- position in the pattern, and, optionally, one item of data originally +- supplied by the caller of the matching function. The callout function ++ During matching, when PCRE reaches a callout point, the external func- ++ tion is called. It is provided with the number of the callout, the ++ position in the pattern, and, optionally, one item of data originally ++ supplied by the caller of the matching function. The callout function + may cause matching to proceed, to backtrack, or to fail altogether. + +- By default, PCRE implements a number of optimizations at compile time +- and matching time, and one side-effect is that sometimes callouts are +- skipped. If you need all possible callouts to happen, you need to set +- options that disable the relevant optimizations. More details, and a +- complete description of the interface to the callout function, are ++ By default, PCRE implements a number of optimizations at compile time ++ and matching time, and one side-effect is that sometimes callouts are ++ skipped. If you need all possible callouts to happen, you need to set ++ options that disable the relevant optimizations. More details, and a ++ complete description of the interface to the callout function, are + given in the pcrecallout documentation. + + + BACKTRACKING CONTROL + +- Perl 5.10 introduced a number of "Special Backtracking Control Verbs", +- which are still described in the Perl documentation as "experimental +- and subject to change or removal in a future version of Perl". It goes +- on to say: "Their usage in production code should be noted to avoid +- problems during upgrades." The same remarks apply to the PCRE features ++ Perl 5.10 introduced a number of "Special Backtracking Control Verbs", ++ which are still described in the Perl documentation as "experimental ++ and subject to change or removal in a future version of Perl". It goes ++ on to say: "Their usage in production code should be noted to avoid ++ problems during upgrades." The same remarks apply to the PCRE features + described in this section. + +- The new verbs make use of what was previously invalid syntax: an open- ++ The new verbs make use of what was previously invalid syntax: an open- + ing parenthesis followed by an asterisk. They are generally of the form +- (*VERB) or (*VERB:NAME). Some may take either form, possibly behaving +- differently depending on whether or not a name is present. A name is ++ (*VERB) or (*VERB:NAME). Some may take either form, possibly behaving ++ differently depending on whether or not a name is present. A name is + any sequence of characters that does not include a closing parenthesis. + The maximum length of name is 255 in the 8-bit library and 65535 in the +- 16-bit and 32-bit libraries. If the name is empty, that is, if the +- closing parenthesis immediately follows the colon, the effect is as if +- the colon were not there. Any number of these verbs may occur in a ++ 16-bit and 32-bit libraries. If the name is empty, that is, if the ++ closing parenthesis immediately follows the colon, the effect is as if ++ the colon were not there. Any number of these verbs may occur in a + pattern. + +- Since these verbs are specifically related to backtracking, most of +- them can be used only when the pattern is to be matched using one of +- the traditional matching functions, because these use a backtracking +- algorithm. With the exception of (*FAIL), which behaves like a failing +- negative assertion, the backtracking control verbs cause an error if ++ Since these verbs are specifically related to backtracking, most of ++ them can be used only when the pattern is to be matched using one of ++ the traditional matching functions, because these use a backtracking ++ algorithm. With the exception of (*FAIL), which behaves like a failing ++ negative assertion, the backtracking control verbs cause an error if + encountered by a DFA matching function. + +- The behaviour of these verbs in repeated groups, assertions, and in ++ The behaviour of these verbs in repeated groups, assertions, and in + subpatterns called as subroutines (whether or not recursively) is docu- + mented below. + + Optimizations that affect backtracking verbs + +- PCRE contains some optimizations that are used to speed up matching by ++ PCRE contains some optimizations that are used to speed up matching by + running some checks at the start of each match attempt. For example, it +- may know the minimum length of matching subject, or that a particular ++ may know the minimum length of matching subject, or that a particular + character must be present. When one of these optimizations bypasses the +- running of a match, any included backtracking verbs will not, of ++ running of a match, any included backtracking verbs will not, of + course, be processed. You can suppress the start-of-match optimizations +- by setting the PCRE_NO_START_OPTIMIZE option when calling pcre_com- ++ by setting the PCRE_NO_START_OPTIMIZE option when calling pcre_com- + pile() or pcre_exec(), or by starting the pattern with (*NO_START_OPT). + There is more discussion of this option in the section entitled "Option + bits for pcre_exec()" in the pcreapi documentation. + +- Experiments with Perl suggest that it too has similar optimizations, ++ Experiments with Perl suggest that it too has similar optimizations, + sometimes leading to anomalous results. + + Verbs that act immediately + +- The following verbs act as soon as they are encountered. They may not ++ The following verbs act as soon as they are encountered. They may not + be followed by a name. + + (*ACCEPT) + +- This verb causes the match to end successfully, skipping the remainder +- of the pattern. However, when it is inside a subpattern that is called +- as a subroutine, only that subpattern is ended successfully. Matching ++ This verb causes the match to end successfully, skipping the remainder ++ of the pattern. However, when it is inside a subpattern that is called ++ as a subroutine, only that subpattern is ended successfully. Matching + then continues at the outer level. If (*ACCEPT) in triggered in a posi- +- tive assertion, the assertion succeeds; in a negative assertion, the ++ tive assertion, the assertion succeeds; in a negative assertion, the + assertion fails. + +- If (*ACCEPT) is inside capturing parentheses, the data so far is cap- ++ If (*ACCEPT) is inside capturing parentheses, the data so far is cap- + tured. For example: + + A((?:A|B(*ACCEPT)|C)D) + +- This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap- ++ This matches "AB", "AAD", or "ACD"; when it matches "AB", "B" is cap- + tured by the outer parentheses. + + (*FAIL) or (*F) + +- This verb causes a matching failure, forcing backtracking to occur. It +- is equivalent to (?!) but easier to read. The Perl documentation notes +- that it is probably useful only when combined with (?{}) or (??{}). +- Those are, of course, Perl features that are not present in PCRE. The +- nearest equivalent is the callout feature, as for example in this pat- ++ This verb causes a matching failure, forcing backtracking to occur. It ++ is equivalent to (?!) but easier to read. The Perl documentation notes ++ that it is probably useful only when combined with (?{}) or (??{}). ++ Those are, of course, Perl features that are not present in PCRE. The ++ nearest equivalent is the callout feature, as for example in this pat- + tern: + + a+(?C)(*FAIL) + +- A match with the string "aaaa" always fails, but the callout is taken ++ A match with the string "aaaa" always fails, but the callout is taken + before each backtrack happens (in this example, 10 times). + + Recording which path was taken + +- There is one verb whose main purpose is to track how a match was +- arrived at, though it also has a secondary use in conjunction with ++ There is one verb whose main purpose is to track how a match was ++ arrived at, though it also has a secondary use in conjunction with + advancing the match starting point (see (*SKIP) below). + + (*MARK:NAME) or (*:NAME) + +- A name is always required with this verb. There may be as many +- instances of (*MARK) as you like in a pattern, and their names do not ++ A name is always required with this verb. There may be as many ++ instances of (*MARK) as you like in a pattern, and their names do not + have to be unique. + +- When a match succeeds, the name of the last-encountered (*MARK:NAME), +- (*PRUNE:NAME), or (*THEN:NAME) on the matching path is passed back to +- the caller as described in the section entitled "Extra data for +- pcre_exec()" in the pcreapi documentation. Here is an example of +- pcretest output, where the /K modifier requests the retrieval and out- ++ When a match succeeds, the name of the last-encountered (*MARK:NAME), ++ (*PRUNE:NAME), or (*THEN:NAME) on the matching path is passed back to ++ the caller as described in the section entitled "Extra data for ++ pcre_exec()" in the pcreapi documentation. Here is an example of ++ pcretest output, where the /K modifier requests the retrieval and out- + putting of (*MARK) data: + + re> /X(*MARK:A)Y|X(*MARK:B)Z/K +@@ -7355,73 +7379,73 @@ BACKTRACKING CONTROL + MK: B + + The (*MARK) name is tagged with "MK:" in this output, and in this exam- +- ple it indicates which of the two alternatives matched. This is a more +- efficient way of obtaining this information than putting each alterna- ++ ple it indicates which of the two alternatives matched. This is a more ++ efficient way of obtaining this information than putting each alterna- + tive in its own capturing parentheses. + +- If a verb with a name is encountered in a positive assertion that is +- true, the name is recorded and passed back if it is the last-encoun- ++ If a verb with a name is encountered in a positive assertion that is ++ true, the name is recorded and passed back if it is the last-encoun- + tered. This does not happen for negative assertions or failing positive + assertions. + +- After a partial match or a failed match, the last encountered name in ++ After a partial match or a failed match, the last encountered name in + the entire match process is returned. For example: + + re> /X(*MARK:A)Y|X(*MARK:B)Z/K + data> XP + No match, mark = B + +- Note that in this unanchored example the mark is retained from the ++ Note that in this unanchored example the mark is retained from the + match attempt that started at the letter "X" in the subject. Subsequent + match attempts starting at "P" and then with an empty string do not get + as far as the (*MARK) item, but nevertheless do not reset it. + +- If you are interested in (*MARK) values after failed matches, you +- should probably set the PCRE_NO_START_OPTIMIZE option (see above) to ++ If you are interested in (*MARK) values after failed matches, you ++ should probably set the PCRE_NO_START_OPTIMIZE option (see above) to + ensure that the match is always attempted. + + Verbs that act after backtracking + + The following verbs do nothing when they are encountered. Matching con- +- tinues with what follows, but if there is no subsequent match, causing +- a backtrack to the verb, a failure is forced. That is, backtracking +- cannot pass to the left of the verb. However, when one of these verbs ++ tinues with what follows, but if there is no subsequent match, causing ++ a backtrack to the verb, a failure is forced. That is, backtracking ++ cannot pass to the left of the verb. However, when one of these verbs + appears inside an atomic group or an assertion that is true, its effect +- is confined to that group, because once the group has been matched, +- there is never any backtracking into it. In this situation, backtrack- +- ing can "jump back" to the left of the entire atomic group or asser- +- tion. (Remember also, as stated above, that this localization also ++ is confined to that group, because once the group has been matched, ++ there is never any backtracking into it. In this situation, backtrack- ++ ing can "jump back" to the left of the entire atomic group or asser- ++ tion. (Remember also, as stated above, that this localization also + applies in subroutine calls.) + +- These verbs differ in exactly what kind of failure occurs when back- +- tracking reaches them. The behaviour described below is what happens +- when the verb is not in a subroutine or an assertion. Subsequent sec- ++ These verbs differ in exactly what kind of failure occurs when back- ++ tracking reaches them. The behaviour described below is what happens ++ when the verb is not in a subroutine or an assertion. Subsequent sec- + tions cover these special cases. + + (*COMMIT) + +- This verb, which may not be followed by a name, causes the whole match ++ This verb, which may not be followed by a name, causes the whole match + to fail outright if there is a later matching failure that causes back- +- tracking to reach it. Even if the pattern is unanchored, no further ++ tracking to reach it. Even if the pattern is unanchored, no further + attempts to find a match by advancing the starting point take place. If +- (*COMMIT) is the only backtracking verb that is encountered, once it ++ (*COMMIT) is the only backtracking verb that is encountered, once it + has been passed pcre_exec() is committed to finding a match at the cur- + rent starting point, or not at all. For example: + + a+(*COMMIT)b + +- This matches "xxaab" but not "aacaab". It can be thought of as a kind ++ This matches "xxaab" but not "aacaab". It can be thought of as a kind + of dynamic anchor, or "I've started, so I must finish." The name of the +- most recently passed (*MARK) in the path is passed back when (*COMMIT) ++ most recently passed (*MARK) in the path is passed back when (*COMMIT) + forces a match failure. + +- If there is more than one backtracking verb in a pattern, a different +- one that follows (*COMMIT) may be triggered first, so merely passing ++ If there is more than one backtracking verb in a pattern, a different ++ one that follows (*COMMIT) may be triggered first, so merely passing + (*COMMIT) during a match does not always guarantee that a match must be + at this starting point. + +- Note that (*COMMIT) at the start of a pattern is not the same as an +- anchor, unless PCRE's start-of-match optimizations are turned off, as ++ Note that (*COMMIT) at the start of a pattern is not the same as an ++ anchor, unless PCRE's start-of-match optimizations are turned off, as + shown in this output from pcretest: + + re> /(*COMMIT)abc/ +@@ -7432,207 +7456,207 @@ BACKTRACKING CONTROL + + For this pattern, PCRE knows that any match must start with "a", so the + optimization skips along the subject to "a" before applying the pattern +- to the first set of data. The match attempt then succeeds. In the sec- +- ond set of data, the escape sequence \Y is interpreted by the pcretest +- program. It causes the PCRE_NO_START_OPTIMIZE option to be set when ++ to the first set of data. The match attempt then succeeds. In the sec- ++ ond set of data, the escape sequence \Y is interpreted by the pcretest ++ program. It causes the PCRE_NO_START_OPTIMIZE option to be set when + pcre_exec() is called. This disables the optimization that skips along + to the first character. The pattern is now applied starting at "x", and +- so the (*COMMIT) causes the match to fail without trying any other ++ so the (*COMMIT) causes the match to fail without trying any other + starting points. + + (*PRUNE) or (*PRUNE:NAME) + +- This verb causes the match to fail at the current starting position in ++ This verb causes the match to fail at the current starting position in + the subject if there is a later matching failure that causes backtrack- +- ing to reach it. If the pattern is unanchored, the normal "bumpalong" +- advance to the next starting character then happens. Backtracking can +- occur as usual to the left of (*PRUNE), before it is reached, or when +- matching to the right of (*PRUNE), but if there is no match to the +- right, backtracking cannot cross (*PRUNE). In simple cases, the use of +- (*PRUNE) is just an alternative to an atomic group or possessive quan- ++ ing to reach it. If the pattern is unanchored, the normal "bumpalong" ++ advance to the next starting character then happens. Backtracking can ++ occur as usual to the left of (*PRUNE), before it is reached, or when ++ matching to the right of (*PRUNE), but if there is no match to the ++ right, backtracking cannot cross (*PRUNE). In simple cases, the use of ++ (*PRUNE) is just an alternative to an atomic group or possessive quan- + tifier, but there are some uses of (*PRUNE) that cannot be expressed in +- any other way. In an anchored pattern (*PRUNE) has the same effect as ++ any other way. In an anchored pattern (*PRUNE) has the same effect as + (*COMMIT). + + The behaviour of (*PRUNE:NAME) is the not the same as +- (*MARK:NAME)(*PRUNE). It is like (*MARK:NAME) in that the name is +- remembered for passing back to the caller. However, (*SKIP:NAME) ++ (*MARK:NAME)(*PRUNE). It is like (*MARK:NAME) in that the name is ++ remembered for passing back to the caller. However, (*SKIP:NAME) + searches only for names set with (*MARK). + + (*SKIP) + +- This verb, when given without a name, is like (*PRUNE), except that if +- the pattern is unanchored, the "bumpalong" advance is not to the next ++ This verb, when given without a name, is like (*PRUNE), except that if ++ the pattern is unanchored, the "bumpalong" advance is not to the next + character, but to the position in the subject where (*SKIP) was encoun- +- tered. (*SKIP) signifies that whatever text was matched leading up to ++ tered. (*SKIP) signifies that whatever text was matched leading up to + it cannot be part of a successful match. Consider: + + a+(*SKIP)b + +- If the subject is "aaaac...", after the first match attempt fails +- (starting at the first character in the string), the starting point ++ If the subject is "aaaac...", after the first match attempt fails ++ (starting at the first character in the string), the starting point + skips on to start the next attempt at "c". Note that a possessive quan- +- tifer does not have the same effect as this example; although it would +- suppress backtracking during the first match attempt, the second +- attempt would start at the second character instead of skipping on to ++ tifer does not have the same effect as this example; although it would ++ suppress backtracking during the first match attempt, the second ++ attempt would start at the second character instead of skipping on to + "c". + + (*SKIP:NAME) + + When (*SKIP) has an associated name, its behaviour is modified. When it + is triggered, the previous path through the pattern is searched for the +- most recent (*MARK) that has the same name. If one is found, the ++ most recent (*MARK) that has the same name. If one is found, the + "bumpalong" advance is to the subject position that corresponds to that + (*MARK) instead of to where (*SKIP) was encountered. If no (*MARK) with + a matching name is found, the (*SKIP) is ignored. + +- Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It ++ Note that (*SKIP:NAME) searches only for names set by (*MARK:NAME). It + ignores names that are set by (*PRUNE:NAME) or (*THEN:NAME). + + (*THEN) or (*THEN:NAME) + +- This verb causes a skip to the next innermost alternative when back- +- tracking reaches it. That is, it cancels any further backtracking +- within the current alternative. Its name comes from the observation ++ This verb causes a skip to the next innermost alternative when back- ++ tracking reaches it. That is, it cancels any further backtracking ++ within the current alternative. Its name comes from the observation + that it can be used for a pattern-based if-then-else block: + + ( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ... + +- If the COND1 pattern matches, FOO is tried (and possibly further items +- after the end of the group if FOO succeeds); on failure, the matcher +- skips to the second alternative and tries COND2, without backtracking +- into COND1. If that succeeds and BAR fails, COND3 is tried. If subse- +- quently BAZ fails, there are no more alternatives, so there is a back- +- track to whatever came before the entire group. If (*THEN) is not ++ If the COND1 pattern matches, FOO is tried (and possibly further items ++ after the end of the group if FOO succeeds); on failure, the matcher ++ skips to the second alternative and tries COND2, without backtracking ++ into COND1. If that succeeds and BAR fails, COND3 is tried. If subse- ++ quently BAZ fails, there are no more alternatives, so there is a back- ++ track to whatever came before the entire group. If (*THEN) is not + inside an alternation, it acts like (*PRUNE). + +- The behaviour of (*THEN:NAME) is the not the same as +- (*MARK:NAME)(*THEN). It is like (*MARK:NAME) in that the name is +- remembered for passing back to the caller. However, (*SKIP:NAME) ++ The behaviour of (*THEN:NAME) is the not the same as ++ (*MARK:NAME)(*THEN). It is like (*MARK:NAME) in that the name is ++ remembered for passing back to the caller. However, (*SKIP:NAME) + searches only for names set with (*MARK). + +- A subpattern that does not contain a | character is just a part of the +- enclosing alternative; it is not a nested alternation with only one +- alternative. The effect of (*THEN) extends beyond such a subpattern to +- the enclosing alternative. Consider this pattern, where A, B, etc. are +- complex pattern fragments that do not contain any | characters at this ++ A subpattern that does not contain a | character is just a part of the ++ enclosing alternative; it is not a nested alternation with only one ++ alternative. The effect of (*THEN) extends beyond such a subpattern to ++ the enclosing alternative. Consider this pattern, where A, B, etc. are ++ complex pattern fragments that do not contain any | characters at this + level: + + A (B(*THEN)C) | D + +- If A and B are matched, but there is a failure in C, matching does not ++ If A and B are matched, but there is a failure in C, matching does not + backtrack into A; instead it moves to the next alternative, that is, D. +- However, if the subpattern containing (*THEN) is given an alternative, ++ However, if the subpattern containing (*THEN) is given an alternative, + it behaves differently: + + A (B(*THEN)C | (*FAIL)) | D + +- The effect of (*THEN) is now confined to the inner subpattern. After a ++ The effect of (*THEN) is now confined to the inner subpattern. After a + failure in C, matching moves to (*FAIL), which causes the whole subpat- +- tern to fail because there are no more alternatives to try. In this ++ tern to fail because there are no more alternatives to try. In this + case, matching does now backtrack into A. + +- Note that a conditional subpattern is not considered as having two +- alternatives, because only one is ever used. In other words, the | ++ Note that a conditional subpattern is not considered as having two ++ alternatives, because only one is ever used. In other words, the | + character in a conditional subpattern has a different meaning. Ignoring + white space, consider: + + ^.*? (?(?=a) a | b(*THEN)c ) + +- If the subject is "ba", this pattern does not match. Because .*? is +- ungreedy, it initially matches zero characters. The condition (?=a) +- then fails, the character "b" is matched, but "c" is not. At this +- point, matching does not backtrack to .*? as might perhaps be expected +- from the presence of the | character. The conditional subpattern is ++ If the subject is "ba", this pattern does not match. Because .*? is ++ ungreedy, it initially matches zero characters. The condition (?=a) ++ then fails, the character "b" is matched, but "c" is not. At this ++ point, matching does not backtrack to .*? as might perhaps be expected ++ from the presence of the | character. The conditional subpattern is + part of the single alternative that comprises the whole pattern, and so +- the match fails. (If there was a backtrack into .*?, allowing it to ++ the match fails. (If there was a backtrack into .*?, allowing it to + match "b", the match would succeed.) + +- The verbs just described provide four different "strengths" of control ++ The verbs just described provide four different "strengths" of control + when subsequent matching fails. (*THEN) is the weakest, carrying on the +- match at the next alternative. (*PRUNE) comes next, failing the match +- at the current starting position, but allowing an advance to the next +- character (for an unanchored pattern). (*SKIP) is similar, except that ++ match at the next alternative. (*PRUNE) comes next, failing the match ++ at the current starting position, but allowing an advance to the next ++ character (for an unanchored pattern). (*SKIP) is similar, except that + the advance may be more than one character. (*COMMIT) is the strongest, + causing the entire match to fail. + + More than one backtracking verb + +- If more than one backtracking verb is present in a pattern, the one +- that is backtracked onto first acts. For example, consider this pat- ++ If more than one backtracking verb is present in a pattern, the one ++ that is backtracked onto first acts. For example, consider this pat- + tern, where A, B, etc. are complex pattern fragments: + + (A(*COMMIT)B(*THEN)C|ABD) + +- If A matches but B fails, the backtrack to (*COMMIT) causes the entire ++ If A matches but B fails, the backtrack to (*COMMIT) causes the entire + match to fail. However, if A and B match, but C fails, the backtrack to +- (*THEN) causes the next alternative (ABD) to be tried. This behaviour +- is consistent, but is not always the same as Perl's. It means that if +- two or more backtracking verbs appear in succession, all the the last ++ (*THEN) causes the next alternative (ABD) to be tried. This behaviour ++ is consistent, but is not always the same as Perl's. It means that if ++ two or more backtracking verbs appear in succession, all the the last + of them has no effect. Consider this example: + + ...(*COMMIT)(*PRUNE)... + + If there is a matching failure to the right, backtracking onto (*PRUNE) +- causes it to be triggered, and its action is taken. There can never be ++ causes it to be triggered, and its action is taken. There can never be + a backtrack onto (*COMMIT). + + Backtracking verbs in repeated groups + +- PCRE differs from Perl in its handling of backtracking verbs in ++ PCRE differs from Perl in its handling of backtracking verbs in + repeated groups. For example, consider: + + /(a(*COMMIT)b)+ac/ + +- If the subject is "abac", Perl matches, but PCRE fails because the ++ If the subject is "abac", Perl matches, but PCRE fails because the + (*COMMIT) in the second repeat of the group acts. + + Backtracking verbs in assertions + +- (*FAIL) in an assertion has its normal effect: it forces an immediate ++ (*FAIL) in an assertion has its normal effect: it forces an immediate + backtrack. + + (*ACCEPT) in a positive assertion causes the assertion to succeed with- +- out any further processing. In a negative assertion, (*ACCEPT) causes ++ out any further processing. In a negative assertion, (*ACCEPT) causes + the assertion to fail without any further processing. + +- The other backtracking verbs are not treated specially if they appear +- in a positive assertion. In particular, (*THEN) skips to the next +- alternative in the innermost enclosing group that has alternations, ++ The other backtracking verbs are not treated specially if they appear ++ in a positive assertion. In particular, (*THEN) skips to the next ++ alternative in the innermost enclosing group that has alternations, + whether or not this is within the assertion. + +- Negative assertions are, however, different, in order to ensure that +- changing a positive assertion into a negative assertion changes its ++ Negative assertions are, however, different, in order to ensure that ++ changing a positive assertion into a negative assertion changes its + result. Backtracking into (*COMMIT), (*SKIP), or (*PRUNE) causes a neg- + ative assertion to be true, without considering any further alternative + branches in the assertion. Backtracking into (*THEN) causes it to skip +- to the next enclosing alternative within the assertion (the normal be- +- haviour), but if the assertion does not have such an alternative, ++ to the next enclosing alternative within the assertion (the normal be- ++ haviour), but if the assertion does not have such an alternative, + (*THEN) behaves like (*PRUNE). + + Backtracking verbs in subroutines + +- These behaviours occur whether or not the subpattern is called recur- ++ These behaviours occur whether or not the subpattern is called recur- + sively. Perl's treatment of subroutines is different in some cases. + +- (*FAIL) in a subpattern called as a subroutine has its normal effect: ++ (*FAIL) in a subpattern called as a subroutine has its normal effect: + it forces an immediate backtrack. + +- (*ACCEPT) in a subpattern called as a subroutine causes the subroutine +- match to succeed without any further processing. Matching then contin- ++ (*ACCEPT) in a subpattern called as a subroutine causes the subroutine ++ match to succeed without any further processing. Matching then contin- + ues after the subroutine call. + + (*COMMIT), (*SKIP), and (*PRUNE) in a subpattern called as a subroutine + cause the subroutine match to fail. + +- (*THEN) skips to the next alternative in the innermost enclosing group +- within the subpattern that has alternatives. If there is no such group ++ (*THEN) skips to the next alternative in the innermost enclosing group ++ within the subpattern that has alternatives. If there is no such group + within the subpattern, (*THEN) causes the subroutine match to fail. + + + SEE ALSO + +- pcreapi(3), pcrecallout(3), pcrematching(3), pcresyntax(3), pcre(3), ++ pcreapi(3), pcrecallout(3), pcrematching(3), pcresyntax(3), pcre(3), + pcre16(3), pcre32(3). + + +@@ -7645,8 +7669,8 @@ AUTHOR + + REVISION + +- Last updated: 08 January 2014 +- Copyright (c) 1997-2014 University of Cambridge. ++ Last updated: 14 June 2015 ++ Copyright (c) 1997-2015 University of Cambridge. + ------------------------------------------------------------------------------ + + +diff --git a/ext/pcre/pcrelib/pcre.h b/ext/pcre/pcrelib/pcre.h +index 58ed46a..bf6351f 100644 +--- a/ext/pcre/pcrelib/pcre.h ++++ b/ext/pcre/pcrelib/pcre.h +@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE. + /* The current PCRE version information. */ + + #define PCRE_MAJOR 8 +-#define PCRE_MINOR 37 ++#define PCRE_MINOR 38 + #define PCRE_PRERELEASE +-#define PCRE_DATE 2015-04-28 ++#define PCRE_DATE 2015-11-23 + + /* When an application links to a PCRE DLL in Windows, the symbols that are + imported have to be identified as such. When building PCRE, the appropriate +diff --git a/ext/pcre/pcrelib/pcre_compile.c b/ext/pcre/pcrelib/pcre_compile.c +index 0efad26..4d3b313 100644 +--- a/ext/pcre/pcrelib/pcre_compile.c ++++ b/ext/pcre/pcrelib/pcre_compile.c +@@ -174,7 +174,7 @@ static const short int escapes[] = { + -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, + CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, + CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, +- CHAR_GRAVE_ACCENT, 7, ++ CHAR_GRAVE_ACCENT, ESC_a, + -ESC_b, 0, + -ESC_d, ESC_e, + ESC_f, 0, +@@ -202,9 +202,9 @@ static const short int escapes[] = { + /* 68 */ 0, 0, '|', ',', '%', '_', '>', '?', + /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', +-/* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, ++/* 80 */ 0, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, + /* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, +-/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p, ++/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, + /* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, + /* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, + /* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, +@@ -219,6 +219,12 @@ static const short int escapes[] = { + /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* F8 */ 0, 0, 0, 0, 0, 0, 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 + + +@@ -458,7 +464,7 @@ static const char error_texts[] = + "range out of order in character class\0" + "nothing to repeat\0" + /* 10 */ +- "operand of unlimited repeat could match the empty string\0" /** DEAD **/ ++ "internal error: invalid forward reference offset\0" + "internal error: unexpected repeat\0" + "unrecognized character after (? or (?-\0" + "POSIX named classes are supported only within a class\0" +@@ -527,7 +533,11 @@ static const char error_texts[] = + "different names for subpatterns of the same number are not allowed\0" + "(*MARK) must have an argument\0" + "this version of PCRE is not compiled with Unicode property support\0" ++#ifndef EBCDIC + "\\c must be followed by an 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 opcode in find_fixedlength()\0" +@@ -1425,7 +1435,16 @@ else + c ^= 0x40; + #else /* EBCDIC coding */ + if (c >= CHAR_a && c <= CHAR_z) c += 64; +- c ^= 0xC0; ++ 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 + break; + +@@ -1799,7 +1818,7 @@ for (;;) + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do cc += GET(cc, 1); while (*cc == OP_ALT); +- cc += PRIV(OP_lengths)[*cc]; ++ cc += 1 + LINK_SIZE; + break; + + /* Skip over things that don't match chars */ +@@ -2487,7 +2506,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); + if (c == OP_BRA || c == OP_BRAPOS || + c == OP_CBRA || c == OP_CBRAPOS || + c == OP_ONCE || c == OP_ONCE_NC || +- c == OP_COND) ++ c == OP_COND || c == OP_SCOND) + { + BOOL empty_branch; + if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ +@@ -3886,11 +3905,11 @@ 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 case of \], 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. ++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 +@@ -3917,21 +3936,16 @@ pcre_uchar terminator; /* Don't combine these lines; the Solaris cc */ + terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ + for (++ptr; *ptr != CHAR_NULL; ptr++) + { +- if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) ++ if (*ptr == CHAR_BACKSLASH && ++ (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ++ ptr[1] == CHAR_BACKSLASH)) + ptr++; +- else if (*ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; +- else ++ 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) + { +- if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) +- { +- *endptr = ptr; +- return TRUE; +- } +- if (*ptr == CHAR_LEFT_SQUARE_BRACKET && +- (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || +- ptr[1] == CHAR_EQUALS_SIGN) && +- check_posix_syntax(ptr, endptr)) +- return FALSE; ++ *endptr = ptr; ++ return TRUE; + } + } + return FALSE; +@@ -3985,11 +3999,12 @@ have their offsets adjusted. That one of the jobs of this function. Before it + is called, the partially compiled regex must be temporarily terminated with + OP_END. + +-This function has been extended with the possibility of forward references for +-recursions and subroutine calls. It must also check the list of such references +-for the group we are dealing with. If it finds that one of the recursions in +-the current group is on this list, it adjusts the offset in the list, not the +-value in the reference (which is a group number). ++This function has been extended to cope with forward references for recursions ++and subroutine calls. It must check the list of such references for the ++group we are dealing with. If it finds that one of the recursions in the ++current group is on this list, it does not adjust the value in the reference ++(which is a group number). After the group has been scanned, all the offsets in ++the forward reference list for the group are adjusted. + + Arguments: + group points to the start of the group +@@ -4005,29 +4020,21 @@ static void + adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd, + size_t save_hwm_offset) + { ++int offset; ++pcre_uchar *hc; + pcre_uchar *ptr = group; + + while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) + { +- int offset; +- pcre_uchar *hc; +- +- /* See if this recursion is on the forward reference list. If so, adjust the +- reference. */ +- + for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; + hc += LINK_SIZE) + { + offset = (int)GET(hc, 0); +- if (cd->start_code + offset == ptr + 1) +- { +- PUT(hc, 0, offset + adjust); +- break; +- } ++ if (cd->start_code + offset == ptr + 1) break; + } + +- /* Otherwise, adjust the recursion offset if it's after the start of this +- group. */ ++ /* If we have not found this recursion on the forward reference list, adjust ++ the recursion's offset if it's after the start of this group. */ + + if (hc >= cd->hwm) + { +@@ -4037,6 +4044,15 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) + + ptr += 1 + LINK_SIZE; + } ++ ++/* Now adjust all forward reference offsets for the group. */ ++ ++for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; ++ hc += LINK_SIZE) ++ { ++ offset = (int)GET(hc, 0); ++ PUT(hc, 0, offset + adjust); ++ } + } + + +@@ -4465,7 +4481,7 @@ const pcre_uchar *tempptr; + const pcre_uchar *nestptr = NULL; + pcre_uchar *previous = NULL; + pcre_uchar *previous_callout = NULL; +-size_t save_hwm_offset = 0; ++size_t item_hwm_offset = 0; + pcre_uint8 classbits[32]; + + /* We can fish out the UTF-8 setting once and for all into a BOOL, but we +@@ -4623,8 +4639,7 @@ for (;; ptr++) + /* In the real compile phase, just check the workspace used by the forward + reference list. */ + +- else if (cd->hwm > cd->start_workspace + cd->workspace_size - +- WORK_SIZE_SAFETY_MARGIN) ++ else if (cd->hwm > cd->start_workspace + cd->workspace_size) + { + *errorcodeptr = ERR52; + goto FAILED; +@@ -4767,6 +4782,7 @@ for (;; ptr++) + zeroreqchar = reqchar; + zeroreqcharflags = reqcharflags; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY; + break; + +@@ -4818,6 +4834,7 @@ for (;; ptr++) + /* Handle a real character class. */ + + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + + /* 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. */ +@@ -4923,9 +4940,10 @@ for (;; ptr++) + (which is on the stack). We have to remember that there was XCLASS data, + however. */ + ++ if (class_uchardata > class_uchardata_base) xclass = TRUE; ++ + if (lengthptr != NULL && class_uchardata > class_uchardata_base) + { +- xclass = TRUE; + *lengthptr += (int)(class_uchardata - class_uchardata_base); + class_uchardata = class_uchardata_base; + } +@@ -5028,10 +5046,26 @@ for (;; ptr++) + ptr = tempptr + 1; + continue; + +- /* For all other POSIX classes, no special action is taken in UCP +- mode. Fall through to the non_UCP case. */ ++ /* 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. If we are in a negated POSIX class ++ within a non-negated overall class, characters with code points ++ greater than 255 must all match. In the special case where we have ++ not yet generated any xclass data, and this is the final item in ++ the overall class, we need do nothing: later on, the opcode ++ OP_NCLASS will be used to indicate that characters greater than 255 ++ are acceptable. If we have already seen an xclass item or one may ++ follow (we have to assume that it might if this is not the end of ++ the class), explicitly match all wide codepoints. */ + + default: ++ if (!negate_class && local_negate && ++ (xclass || tempptr[2] != CHAR_RIGHT_SQUARE_BRACKET)) ++ { ++ *class_uchardata++ = XCL_RANGE; ++ class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); ++ class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); ++ } + break; + } + } +@@ -5195,9 +5229,9 @@ for (;; ptr++) + cd, PRIV(vspace_list)); + continue; + +-#ifdef SUPPORT_UCP + case ESC_p: + case ESC_P: ++#ifdef SUPPORT_UCP + { + BOOL negated; + unsigned int ptype = 0, pdata = 0; +@@ -5211,6 +5245,9 @@ for (;; ptr++) + class_has_8bitchar--; /* Undo! */ + continue; + } ++#else ++ *errorcodeptr = ERR45; ++ goto FAILED; + #endif + /* Unrecognized escapes are faulted if PCRE is running in its + strict mode. By default, for compatibility with Perl, they are +@@ -5367,16 +5404,20 @@ for (;; ptr++) + CLASS_SINGLE_CHARACTER: + if (class_one_char < 2) class_one_char++; + +- /* If class_one_char is 1, we have the first single character in the +- class, and there have been no prior ranges, or XCLASS items generated by +- escapes. If this is the final character in the class, we can optimize by +- turning the item into a 1-character OP_CHAR[I] if it's positive, or +- OP_NOT[I] if it's negative. In the positive case, it can cause firstchar +- to be set. Otherwise, there can be no first char if this item is first, +- whatever repeat count may follow. In the case of reqchar, save the +- previous value for reinstating. */ ++ /* If xclass_has_prop is false and class_one_char is 1, we have the first ++ single character in the class, and there have been no prior ranges, or ++ XCLASS items generated by escapes. If this is the final character in the ++ class, we can optimize by turning the item into a 1-character OP_CHAR[I] ++ if it's positive, or OP_NOT[I] if it's negative. In the positive case, it ++ can cause firstchar to be set. Otherwise, there can be no first char if ++ this item is first, whatever repeat count may follow. In the case of ++ reqchar, save the previous value for reinstating. */ + +- if (!inescq && class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) ++ if (!inescq && ++#ifdef SUPPORT_UCP ++ !xclass_has_prop && ++#endif ++ class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) + { + ptr++; + zeroreqchar = reqchar; +@@ -5492,9 +5533,10 @@ for (;; ptr++) + actual compiled code. */ + + #ifdef SUPPORT_UTF +- if (xclass && (!should_flip_negation || (options & PCRE_UCP) != 0)) ++ if (xclass && (xclass_has_prop || !should_flip_negation || ++ (options & PCRE_UCP) != 0)) + #elif !defined COMPILE_PCRE8 +- if (xclass && !should_flip_negation) ++ if (xclass && (xclass_has_prop || !should_flip_negation)) + #endif + #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 + { +@@ -5930,7 +5972,7 @@ for (;; ptr++) + { + register int i; + int len = (int)(code - previous); +- size_t base_hwm_offset = save_hwm_offset; ++ size_t base_hwm_offset = item_hwm_offset; + pcre_uchar *bralink = NULL; + pcre_uchar *brazeroptr = NULL; + +@@ -5985,7 +6027,7 @@ for (;; ptr++) + if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ + { + *code = OP_END; +- adjust_recurse(previous, 1, utf, cd, save_hwm_offset); ++ adjust_recurse(previous, 1, utf, cd, item_hwm_offset); + memmove(previous + 1, previous, IN_UCHARS(len)); + code++; + if (repeat_max == 0) +@@ -6009,7 +6051,7 @@ for (;; ptr++) + { + int offset; + *code = OP_END; +- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len)); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; +@@ -6254,6 +6296,12 @@ for (;; ptr++) + while (*scode == OP_ALT); + } + ++ /* A conditional group with only one branch has an implicit empty ++ alternative branch. */ ++ ++ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) ++ *bracode = OP_SCOND; ++ + /* Handle possessive quantifiers. */ + + if (possessive_quantifier) +@@ -6267,11 +6315,11 @@ for (;; ptr++) + { + int nlen = (int)(code - bracode); + *code = OP_END; +- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen)); + code += 1 + LINK_SIZE; + nlen += 1 + LINK_SIZE; +- *bracode = OP_BRAPOS; ++ *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; + *code++ = OP_KETRPOS; + PUTINC(code, 0, nlen); + PUT(bracode, 1, nlen); +@@ -6401,7 +6449,7 @@ for (;; ptr++) + else + { + *code = OP_END; +- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; +@@ -6450,7 +6498,7 @@ for (;; ptr++) + + default: + *code = OP_END; +- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset); ++ adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); + memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); + code += 1 + LINK_SIZE; + len += 1 + LINK_SIZE; +@@ -6586,9 +6634,17 @@ for (;; ptr++) + goto FAILED; + } + setverb = *code++ = verbs[i].op_arg; +- *code++ = arglen; +- memcpy(code, arg, IN_UCHARS(arglen)); +- code += arglen; ++ if (lengthptr != NULL) /* In pass 1 just add in the length */ ++ { /* to avoid potential workspace */ ++ *lengthptr += arglen; /* overflow. */ ++ *code++ = 0; ++ } ++ else ++ { ++ *code++ = arglen; ++ memcpy(code, arg, IN_UCHARS(arglen)); ++ code += arglen; ++ } + *code++ = 0; + } + +@@ -6623,7 +6679,7 @@ for (;; ptr++) + newoptions = options; + skipbytes = 0; + bravalue = OP_CBRA; +- save_hwm_offset = cd->hwm - cd->start_workspace; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + reset_bracount = FALSE; + + /* Deal with the extended parentheses; all are introduced by '?', and the +@@ -6641,6 +6697,7 @@ for (;; ptr++) + /* ------------------------------------------------------------ */ + case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ + reset_bracount = TRUE; ++ cd->dupgroups = TRUE; /* Record (?| encountered */ + /* Fall through */ + + /* ------------------------------------------------------------ */ +@@ -6741,6 +6798,12 @@ for (;; ptr++) + { + while (IS_DIGIT(*ptr)) + { ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ while (IS_DIGIT(*ptr)) ptr++; ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + (int)(*ptr - CHAR_0); + ptr++; + } +@@ -6769,7 +6832,7 @@ for (;; ptr++) + ptr++; + } + namelen = (int)(ptr - name); +- if (lengthptr != NULL) *lengthptr += IMM2_SIZE; ++ if (lengthptr != NULL) skipbytes += IMM2_SIZE; + } + + /* Check the terminator */ +@@ -6875,6 +6938,11 @@ for (;; ptr++) + *errorcodeptr = ERR15; + goto FAILED; + } ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + name[i] - CHAR_0; + } + if (recno == 0) recno = RREF_ANY; +@@ -7151,6 +7219,7 @@ for (;; ptr++) + if (lengthptr != NULL) + { + named_group *ng; ++ recno = 0; + + if (namelen == 0) + { +@@ -7168,20 +7237,6 @@ for (;; ptr++) + goto FAILED; + } + +- /* The name table does not exist in the first pass; instead we must +- scan the list of names encountered so far in order to get the +- number. If the name is not found, set the value to 0 for a forward +- reference. */ +- +- ng = cd->named_groups; +- for (i = 0; i < cd->names_found; i++, ng++) +- { +- if (namelen == ng->length && +- STRNCMP_UC_UC(name, ng->name, namelen) == 0) +- break; +- } +- recno = (i < cd->names_found)? ng->number : 0; +- + /* Count named back references. */ + + if (!is_recurse) cd->namedrefcount++; +@@ -7191,6 +7246,56 @@ for (;; ptr++) + 16-bit data item. */ + + *lengthptr += IMM2_SIZE; ++ ++ /* If this is a forward reference and we are within a (?|...) group, ++ the reference may end up as the number of a group which we are ++ currently inside, that is, it could be a recursive reference. In the ++ real compile this will be picked up and the reference wrapped with ++ OP_ONCE to make it atomic, so we must space in case this occurs. */ ++ ++ /* In fact, this can happen for a non-forward reference because ++ another group with the same number might be created later. This ++ issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance ++ only mode, we finesse the bug by allowing more memory always. */ ++ ++ *lengthptr += 2 + 2*LINK_SIZE; ++ ++ /* It is even worse than that. The current reference may be to an ++ existing named group with a different number (so apparently not ++ recursive) but which later on is also attached to a group with the ++ current number. This can only happen if $(| has been previous ++ encountered. In that case, we allow yet more memory, just in case. ++ (Again, this is fixed "properly" in PCRE2. */ ++ ++ if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE; ++ ++ /* Otherwise, check for recursion here. The name table does not exist ++ in the first pass; instead we must scan the list of names encountered ++ so far in order to get the number. If the name is not found, leave ++ the value of recno as 0 for a forward reference. */ ++ ++ else ++ { ++ ng = cd->named_groups; ++ for (i = 0; i < cd->names_found; i++, ng++) ++ { ++ if (namelen == ng->length && ++ STRNCMP_UC_UC(name, ng->name, namelen) == 0) ++ { ++ open_capitem *oc; ++ recno = ng->number; ++ if (is_recurse) break; ++ for (oc = cd->open_caps; oc != NULL; oc = oc->next) ++ { ++ if (oc->number == recno) ++ { ++ oc->flag = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } + } + + /* In the real compile, search the name table. We check the name +@@ -7237,8 +7342,6 @@ for (;; ptr++) + for (i++; i < cd->names_found; i++) + { + if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break; +- +- + count++; + cslot += cd->name_entry_size; + } +@@ -7247,6 +7350,7 @@ for (;; ptr++) + { + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF; + PUT2INC(code, 0, index); + PUT2INC(code, 0, count); +@@ -7284,9 +7388,14 @@ for (;; ptr++) + + + /* ------------------------------------------------------------ */ +- case CHAR_R: /* Recursion */ +- ptr++; /* Same as (?0) */ +- /* Fall through */ ++ case CHAR_R: /* Recursion, same as (?0) */ ++ recno = 0; ++ if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) ++ { ++ *errorcodeptr = ERR29; ++ goto FAILED; ++ } ++ goto HANDLE_RECURSION; + + + /* ------------------------------------------------------------ */ +@@ -7323,7 +7432,15 @@ for (;; ptr++) + + recno = 0; + while(IS_DIGIT(*ptr)) ++ { ++ if (recno > INT_MAX / 10 - 1) /* Integer overflow */ ++ { ++ while (IS_DIGIT(*ptr)) ptr++; ++ *errorcodeptr = ERR61; ++ goto FAILED; ++ } + recno = recno * 10 + *ptr++ - CHAR_0; ++ } + + if (*ptr != (pcre_uchar)terminator) + { +@@ -7360,6 +7477,7 @@ for (;; ptr++) + HANDLE_RECURSION: + + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + called = cd->start_code; + + /* When we are actually compiling, find the bracket that is being +@@ -7561,7 +7679,11 @@ for (;; ptr++) + previous = NULL; + cd->iscondassert = FALSE; + } +- else previous = code; ++ else ++ { ++ previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; ++ } + + *code = bravalue; + tempcode = code; +@@ -7809,7 +7931,7 @@ for (;; ptr++) + const pcre_uchar *p; + pcre_uint32 cf; + +- save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */ ++ item_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */ + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? + CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; + +@@ -7838,7 +7960,7 @@ for (;; ptr++) + if (*p != (pcre_uchar)terminator) + { + *errorcodeptr = ERR57; +- break; ++ goto FAILED; + } + ptr++; + goto HANDLE_NUMERICAL_RECURSION; +@@ -7853,7 +7975,7 @@ for (;; ptr++) + ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) + { + *errorcodeptr = ERR69; +- break; ++ goto FAILED; + } + is_recurse = FALSE; + terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? +@@ -7877,6 +7999,7 @@ for (;; ptr++) + HANDLE_REFERENCE: + if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF; + PUT2INC(code, 0, recno); + cd->backref_map |= (recno < 32)? (1 << recno) : 1; +@@ -7906,6 +8029,7 @@ for (;; ptr++) + if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) + goto FAILED; + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; +@@ -7946,6 +8070,7 @@ for (;; ptr++) + + { + previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; + } + } +@@ -7989,6 +8114,7 @@ for (;; ptr++) + + ONE_CHAR: + previous = code; ++ item_hwm_offset = cd->hwm - cd->start_workspace; + + /* For caseless UTF-8 mode when UCP support is available, check whether + this character has more than one other case. If so, generate a special +@@ -9164,6 +9290,7 @@ cd->names_found = 0; + cd->name_entry_size = 0; + cd->name_table = NULL; + cd->dupnames = FALSE; ++cd->dupgroups = FALSE; + cd->namedrefcount = 0; + cd->start_code = cworkspace; + cd->hwm = cworkspace; +@@ -9336,6 +9463,16 @@ if (cd->hwm > cd->start_workspace) + int offset, recno; + cd->hwm -= LINK_SIZE; + offset = GET(cd->hwm, 0); ++ ++ /* Check that the hwm handling hasn't gone wrong. This whole area is ++ rewritten in PCRE2 because there are some obscure cases. */ ++ ++ if (offset == 0 || codestart[offset-1] != OP_RECURSE) ++ { ++ errorcode = ERR10; ++ break; ++ } ++ + recno = GET(codestart, offset); + if (recno != prev_recno) + { +@@ -9366,7 +9503,7 @@ used in this code because at least one compiler gives a warning about loss of + "const" attribute if the cast (pcre_uchar *)codestart is used directly in the + function call. */ + +-if ((options & PCRE_NO_AUTO_POSSESS) == 0) ++if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0) + { + pcre_uchar *temp = (pcre_uchar *)codestart; + auto_possessify(temp, utf, cd); +@@ -9380,7 +9517,7 @@ OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The + exceptional ones forgo this. We scan the pattern to check that they are fixed + length, and set their lengths. */ + +-if (cd->check_lookbehind) ++if (errorcode == 0 && cd->check_lookbehind) + { + pcre_uchar *cc = (pcre_uchar *)codestart; + +@@ -9593,4 +9730,3 @@ return (pcre32 *)re; + } + + /* End of pcre_compile.c */ +- +diff --git a/ext/pcre/pcrelib/pcre_exec.c b/ext/pcre/pcrelib/pcre_exec.c +index 3942076..24b23ca 100644 +--- a/ext/pcre/pcrelib/pcre_exec.c ++++ b/ext/pcre/pcrelib/pcre_exec.c +@@ -688,7 +688,7 @@ the alternative names that are used. */ + #define foc number + #define save_mark data + +-/* These statements are here to stop the compiler complaining about uninitialized ++/* These statements are here to stop the compiler complaining about unitialized + variables. */ + + #ifdef SUPPORT_UCP +@@ -6685,7 +6685,8 @@ if (md->offset_vector != NULL) + register int *iend = iptr - re->top_bracket; + if (iend < md->offset_vector + 2) iend = md->offset_vector + 2; + while (--iptr >= iend) *iptr = -1; +- md->offset_vector[0] = md->offset_vector[1] = -1; ++ if (offsetcount > 0) md->offset_vector[0] = -1; ++ if (offsetcount > 1) md->offset_vector[1] = -1; + } + + /* Set up the first character to match, if available. The first_char value is +diff --git a/ext/pcre/pcrelib/pcre_internal.h b/ext/pcre/pcrelib/pcre_internal.h +index 4c4817d..aec1879 100644 +--- a/ext/pcre/pcrelib/pcre_internal.h ++++ b/ext/pcre/pcrelib/pcre_internal.h +@@ -988,7 +988,7 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */ + #ifndef EBCDIC + + #define HSPACE_LIST \ +- CHAR_HT, CHAR_SPACE, 0xa0, \ ++ CHAR_HT, CHAR_SPACE, CHAR_NBSP, \ + 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \ + 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \ + NOTACHAR +@@ -1014,7 +1014,7 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */ + #define HSPACE_BYTE_CASES \ + case CHAR_HT: \ + case CHAR_SPACE: \ +- case 0xa0 /* NBSP */ ++ case CHAR_NBSP + + #define HSPACE_CASES \ + HSPACE_BYTE_CASES: \ +@@ -1041,11 +1041,12 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */ + /* ------ EBCDIC environments ------ */ + + #else +-#define HSPACE_LIST CHAR_HT, CHAR_SPACE ++#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR + + #define HSPACE_BYTE_CASES \ + case CHAR_HT: \ +- case CHAR_SPACE ++ case CHAR_SPACE: \ ++ case CHAR_NBSP + + #define HSPACE_CASES HSPACE_BYTE_CASES + +@@ -1219,6 +1220,7 @@ same code point. */ + + #define CHAR_ESC '\047' + #define CHAR_DEL '\007' ++#define CHAR_NBSP '\x41' + #define STR_ESC "\047" + #define STR_DEL "\007" + +@@ -1233,6 +1235,7 @@ a positive value. */ + #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 +@@ -1610,6 +1613,7 @@ only. */ + #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" +@@ -1766,6 +1770,10 @@ only. */ + + /* Escape items that are just an encoding of a particular data value. */ + ++#ifndef ESC_a ++#define ESC_a CHAR_BEL ++#endif ++ + #ifndef ESC_e + #define ESC_e CHAR_ESC + #endif +@@ -2450,6 +2458,7 @@ typedef struct compile_data { + BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ + BOOL check_lookbehind; /* Lookbehinds need later checking */ + BOOL dupnames; /* Duplicate names exist */ ++ BOOL dupgroups; /* Duplicate groups exist: (?| found */ + BOOL iscondassert; /* Next assert is a condition */ + int nltype; /* Newline type */ + int nllen; /* Newline string length */ +diff --git a/ext/pcre/pcrelib/pcre_jit_compile.c b/ext/pcre/pcrelib/pcre_jit_compile.c +index debdf6e..445de0c 100644 +--- a/ext/pcre/pcrelib/pcre_jit_compile.c ++++ b/ext/pcre/pcrelib/pcre_jit_compile.c +@@ -1064,6 +1064,7 @@ pcre_uchar *alternative; + pcre_uchar *end = NULL; + int private_data_ptr = *private_data_start; + int space, size, bracketlen; ++BOOL repeat_check = TRUE; + + while (cc < ccend) + { +@@ -1071,9 +1072,10 @@ while (cc < ccend) + size = 0; + bracketlen = 0; + if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) +- return; ++ break; + +- if (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND) ++ if (repeat_check && (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) ++ { + if (detect_repeat(common, cc)) + { + /* These brackets are converted to repeats, so no global +@@ -1081,6 +1083,8 @@ while (cc < ccend) + if (cc >= end) + end = bracketend(cc); + } ++ } ++ repeat_check = TRUE; + + switch(*cc) + { +@@ -1136,6 +1140,13 @@ while (cc < ccend) + 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; +@@ -1162,12 +1173,17 @@ while (cc < ccend) + size = 1; + break; + +- CASE_ITERATOR_TYPE_PRIVATE_DATA_2B ++ 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: + size += 1 + 32 / sizeof(pcre_uchar); +@@ -1316,6 +1332,13 @@ while (cc < ccend) + 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. */ +@@ -2220,6 +2243,7 @@ while (current != NULL) + SLJIT_ASSERT_STOP(); + break; + } ++ SLJIT_ASSERT(current > (sljit_sw*)current[-1]); + current = (sljit_sw*)current[-1]; + } + return -1; +@@ -3209,7 +3233,7 @@ bytes[len] = byte; + bytes[0] = len; + } + +-static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars) ++static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uint32 *chars, pcre_uint8 *bytes, int max_chars, pcre_uint32 *rec_count) + { + /* Recursive function, which scans prefix literals. */ + BOOL last, any, caseless; +@@ -3227,9 +3251,14 @@ pcre_uchar othercase[1]; + repeat = 1; + while (TRUE) + { ++ if (*rec_count == 0) ++ return 0; ++ (*rec_count)--; ++ + last = TRUE; + any = FALSE; + caseless = FALSE; ++ + switch (*cc) + { + case OP_CHARI: +@@ -3291,7 +3320,7 @@ while (TRUE) + #ifdef SUPPORT_UTF + if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); + #endif +- max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars); ++ max_chars = scan_prefix(common, cc + len, chars, bytes, max_chars, rec_count); + if (max_chars == 0) + return consumed; + last = FALSE; +@@ -3314,7 +3343,7 @@ while (TRUE) + alternative = cc + GET(cc, 1); + while (*alternative == OP_ALT) + { +- max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars); ++ max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, bytes, max_chars, rec_count); + if (max_chars == 0) + return consumed; + alternative += GET(alternative, 1); +@@ -3556,6 +3585,7 @@ int i, max, from; + int range_right = -1, range_len = 3 - 1; + sljit_ub *update_table = NULL; + BOOL in_range; ++pcre_uint32 rec_count; + + for (i = 0; i < MAX_N_CHARS; i++) + { +@@ -3564,7 +3594,8 @@ for (i = 0; i < MAX_N_CHARS; i++) + bytes[i * MAX_N_BYTES] = 0; + } + +-max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS); ++rec_count = 10000; ++max = scan_prefix(common, common->start, chars, bytes, MAX_N_CHARS, &rec_count); + + if (max <= 1) + return FALSE; +@@ -4311,8 +4342,10 @@ switch(length) + 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]) + { +@@ -4900,9 +4933,10 @@ else if ((cc[-1] & XCL_MAP) != 0) + if (!check_class_ranges(common, (const pcre_uint8 *)cc, FALSE, TRUE, list)) + { + #ifdef COMPILE_PCRE8 +- SLJIT_ASSERT(common->utf); ++ jump = NULL; ++ if (common->utf) + #endif +- jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); ++ 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); +@@ -4911,7 +4945,10 @@ else if ((cc[-1] & XCL_MAP) != 0) + OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); + add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO)); + +- JUMPHERE(jump); ++#ifdef COMPILE_PCRE8 ++ if (common->utf) ++#endif ++ JUMPHERE(jump); + } + + OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); +@@ -5219,7 +5256,7 @@ while (*cc != XCL_END) + OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL); + + SET_CHAR_OFFSET(0); +- OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xff); ++ OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f); + OP_FLAGS(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_LESS_EQUAL); + + SET_TYPE_OFFSET(ucp_Pc); +@@ -7665,6 +7702,10 @@ while (*cc != OP_KETRPOS) + 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)); + +@@ -7692,6 +7733,10 @@ while (*cc != OP_KETRPOS) + OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_sw), 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)); + +@@ -7704,9 +7749,6 @@ while (*cc != OP_KETRPOS) + } + } + +- if (needs_control_head) +- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); +- + JUMPTO(SLJIT_JUMP, loop); + flush_stubs(common); + +@@ -8441,8 +8483,7 @@ while (cc < ccend) + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0); + } + BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL(); +- if (cc[1] > OP_ASSERTBACK_NOT) +- count_match(common); ++ count_match(common); + break; + + case OP_ONCE: +@@ -9624,7 +9665,7 @@ static SLJIT_INLINE void compile_recurse(compiler_common *common) + DEFINE_COMPILER; + pcre_uchar *cc = common->start + common->currententry->start; + pcre_uchar *ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE); +-pcre_uchar *ccend = bracketend(cc); ++pcre_uchar *ccend = bracketend(cc) - (1 + LINK_SIZE); + BOOL needs_control_head; + int framesize = get_framesize(common, cc, NULL, TRUE, &needs_control_head); + int private_data_size = get_private_data_copy_length(common, ccbegin, ccend, needs_control_head); +@@ -9648,6 +9689,7 @@ set_jumps(common->currententry->calls, common->currententry->entry); + + sljit_emit_fast_enter(compiler, TMP2, 0); + allocate_stack(common, private_data_size + framesize + alternativesize); ++count_match(common); + OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0); + copy_private_data(common, ccbegin, ccend, TRUE, private_data_size + framesize + alternativesize, framesize + alternativesize, needs_control_head); + if (needs_control_head) +@@ -9992,6 +10034,7 @@ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); + OP1(SLJIT_MOV_UI, 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, base)); + OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit)); ++OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); + OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0); + + if (mode == JIT_PARTIAL_SOFT_COMPILE) +diff --git a/ext/pcre/pcrelib/pcre_study.c b/ext/pcre/pcrelib/pcre_study.c +index 998fe23..7fd0ba0 100644 +--- a/ext/pcre/pcrelib/pcre_study.c ++++ b/ext/pcre/pcrelib/pcre_study.c +@@ -71,6 +71,7 @@ rather than bytes. + startcode pointer to start of the whole pattern's code + options the compiling options + recurses chain of recurse_check to catch mutual recursion ++ countptr pointer to call count (to catch over complexity) + + Returns: the minimum length + -1 if \C in UTF-8 mode or (*ACCEPT) was encountered +@@ -80,7 +81,8 @@ Returns: the minimum length + + static int + find_minlength(const REAL_PCRE *re, const pcre_uchar *code, +- const pcre_uchar *startcode, int options, recurse_check *recurses) ++ const pcre_uchar *startcode, int options, recurse_check *recurses, ++ int *countptr) + { + int length = -1; + /* PCRE_UTF16 has the same value as PCRE_UTF8. */ +@@ -90,6 +92,8 @@ recurse_check this_recurse; + register int branchlength = 0; + register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE; + ++if ((*countptr)++ > 1000) return -1; /* too complex */ ++ + if (*code == OP_CBRA || *code == OP_SCBRA || + *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE; + +@@ -131,7 +135,7 @@ for (;;) + case OP_SBRAPOS: + case OP_ONCE: + case OP_ONCE_NC: +- d = find_minlength(re, cc, startcode, options, recurses); ++ d = find_minlength(re, cc, startcode, options, recurses, countptr); + if (d < 0) return d; + branchlength += d; + do cc += GET(cc, 1); while (*cc == OP_ALT); +@@ -415,7 +419,8 @@ for (;;) + int dd; + this_recurse.prev = recurses; + this_recurse.group = cs; +- dd = find_minlength(re, cs, startcode, options, &this_recurse); ++ dd = find_minlength(re, cs, startcode, options, &this_recurse, ++ countptr); + if (dd < d) d = dd; + } + } +@@ -451,7 +456,8 @@ for (;;) + { + this_recurse.prev = recurses; + this_recurse.group = cs; +- d = find_minlength(re, cs, startcode, options, &this_recurse); ++ d = find_minlength(re, cs, startcode, options, &this_recurse, ++ countptr); + } + } + } +@@ -514,7 +520,7 @@ for (;;) + this_recurse.prev = recurses; + this_recurse.group = cs; + branchlength += find_minlength(re, cs, startcode, options, +- &this_recurse); ++ &this_recurse, countptr); + } + } + cc += 1 + LINK_SIZE; +@@ -1453,6 +1459,7 @@ pcre32_study(const pcre32 *external_re, int options, const char **errorptr) + #endif + { + int min; ++int count = 0; + BOOL bits_set = FALSE; + pcre_uint8 start_bits[32]; + PUBL(extra) *extra = NULL; +@@ -1539,7 +1546,7 @@ if ((re->options & PCRE_ANCHORED) == 0 && + + /* Find the minimum length of subject string. */ + +-switch(min = find_minlength(re, code, code, re->options, NULL)) ++switch(min = find_minlength(re, code, code, re->options, NULL, &count)) + { + case -2: *errorptr = "internal error: missing capturing bracket"; return NULL; + case -3: *errorptr = "internal error: opcode not recognized"; return NULL; +diff --git a/ext/pcre/pcrelib/pcre_xclass.c b/ext/pcre/pcrelib/pcre_xclass.c +index c2b61f0..ef759a5 100644 +--- a/ext/pcre/pcrelib/pcre_xclass.c ++++ b/ext/pcre/pcrelib/pcre_xclass.c +@@ -246,7 +246,7 @@ while ((t = *data++) != XCL_END) + + case PT_PXPUNCT: + if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P || +- (c < 256 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop) ++ (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop) + return !negated; + break; + +diff --git a/ext/pcre/pcrelib/sljit/sljitConfig.h b/ext/pcre/pcrelib/sljit/sljitConfig.h +index 10364c3..1c8a521 100644 +--- a/ext/pcre/pcrelib/sljit/sljitConfig.h ++++ b/ext/pcre/pcrelib/sljit/sljitConfig.h +@@ -96,6 +96,15 @@ + #define SLJIT_EXECUTABLE_ALLOCATOR 1 + #endif + ++/* Force cdecl calling convention even if a better calling ++ convention (e.g. fastcall) is supported by the C compiler. ++ If this option is enabled, C functions without ++ SLJIT_CALL can also be called from JIT code. */ ++#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION ++/* Disabled by default */ ++#define SLJIT_USE_CDECL_CALLING_CONVENTION 0 ++#endif ++ + /* Return with error when an invalid argument is passed. */ + #ifndef SLJIT_ARGUMENT_CHECKS + /* Disabled by default */ +diff --git a/ext/pcre/pcrelib/sljit/sljitConfigInternal.h b/ext/pcre/pcrelib/sljit/sljitConfigInternal.h +index 3284012..16e3547 100644 +--- a/ext/pcre/pcrelib/sljit/sljitConfigInternal.h ++++ b/ext/pcre/pcrelib/sljit/sljitConfigInternal.h +@@ -468,7 +468,12 @@ typedef double sljit_d; + + #ifndef SLJIT_CALL + +-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) ++#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION) ++ ++/* Force cdecl. */ ++#define SLJIT_CALL ++ ++#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + + #if defined(__GNUC__) && !defined(__APPLE__) + +@@ -608,6 +613,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void); + #define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw)) + #endif + ++#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) ++ ++#define SLJIT_NUMBER_OF_REGISTERS 10 ++#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5 ++#define SLJIT_LOCALS_OFFSET_BASE 0 ++ + #elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) + + #define SLJIT_NUMBER_OF_REGISTERS 0 +diff --git a/ext/pcre/pcrelib/sljit/sljitLir.c b/ext/pcre/pcrelib/sljit/sljitLir.c +index 5039a7e..0f1b1c9 100644 +--- a/ext/pcre/pcrelib/sljit/sljitLir.c ++++ b/ext/pcre/pcrelib/sljit/sljitLir.c +@@ -845,8 +845,8 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *comp + } + + static SLJIT_CONST char* op0_names[] = { +- (char*)"breakpoint", (char*)"nop", +- (char*)"lumul", (char*)"lsmul", (char*)"ludiv", (char*)"lsdiv", ++ (char*)"breakpoint", (char*)"nop", (char*)"lumul", (char*)"lsmul", ++ (char*)"udivmod", (char*)"sdivmod", (char*)"udivi", (char*)"sdivi" + }; + + static SLJIT_CONST char* op1_names[] = { +@@ -1036,7 +1036,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler + { + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LSMUL) +- || ((op & ~SLJIT_INT_OP) >= SLJIT_LUDIV && (op & ~SLJIT_INT_OP) <= SLJIT_LSDIV)); ++ || ((op & ~SLJIT_INT_OP) >= SLJIT_UDIVMOD && (op & ~SLJIT_INT_OP) <= SLJIT_SDIVI)); + CHECK_ARGUMENT(op < SLJIT_LUMUL || compiler->scratches >= 2); + #endif + #if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) +@@ -1447,6 +1447,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com + + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw offset) + { ++ SLJIT_UNUSED_ARG(offset); ++ + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + FUNCTION_CHECK_DST(dst, dstw); + #endif +@@ -1462,6 +1464,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_co + + static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw, sljit_sw init_value) + { ++ SLJIT_UNUSED_ARG(init_value); ++ + #if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) + FUNCTION_CHECK_DST(dst, dstw); + #endif +diff --git a/ext/pcre/pcrelib/sljit/sljitLir.h b/ext/pcre/pcrelib/sljit/sljitLir.h +index 24c0f60..2e2e9ac09 100644 +--- a/ext/pcre/pcrelib/sljit/sljitLir.h ++++ b/ext/pcre/pcrelib/sljit/sljitLir.h +@@ -687,7 +687,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler * + #define SLJIT_OP0_BASE 0 + + /* Flags: - (never set any flags) +- Note: breakpoint instruction is not supported by all architectures (namely ppc) ++ Note: breakpoint instruction is not supported by all architectures (e.g. ppc) + It falls back to SLJIT_NOP in those cases. */ + #define SLJIT_BREAKPOINT (SLJIT_OP0_BASE + 0) + /* Flags: - (never set any flags) +@@ -696,24 +696,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler * + #define SLJIT_NOP (SLJIT_OP0_BASE + 1) + /* Flags: - (may destroy flags) + Unsigned multiplication of SLJIT_R0 and SLJIT_R1. +- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */ ++ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */ + #define SLJIT_LUMUL (SLJIT_OP0_BASE + 2) + /* Flags: - (may destroy flags) + Signed multiplication of SLJIT_R0 and SLJIT_R1. +- Result goes to SLJIT_R1:SLJIT_R0 (high:low) word */ ++ Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */ + #define SLJIT_LSMUL (SLJIT_OP0_BASE + 3) + /* Flags: I - (may destroy flags) + Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1. +- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1. +- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */ +-#define SLJIT_LUDIV (SLJIT_OP0_BASE + 4) +-#define SLJIT_ILUDIV (SLJIT_LUDIV | SLJIT_INT_OP) ++ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. */ ++#define SLJIT_UDIVMOD (SLJIT_OP0_BASE + 4) ++#define SLJIT_IUDIVMOD (SLJIT_UDIVMOD | SLJIT_INT_OP) + /* Flags: I - (may destroy flags) + Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1. +- The result is placed in SLJIT_R0 and the remainder goes to SLJIT_R1. +- Note: if SLJIT_R1 contains 0, the behaviour is undefined. */ +-#define SLJIT_LSDIV (SLJIT_OP0_BASE + 5) +-#define SLJIT_ILSDIV (SLJIT_LSDIV | SLJIT_INT_OP) ++ The result is placed into SLJIT_R0 and the remainder into SLJIT_R1. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00), ++ the behaviour is undefined. */ ++#define SLJIT_SDIVMOD (SLJIT_OP0_BASE + 5) ++#define SLJIT_ISDIVMOD (SLJIT_SDIVMOD | SLJIT_INT_OP) ++/* Flags: I - (may destroy flags) ++ Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1. ++ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: SLJIT_SDIV is single precision divide. */ ++#define SLJIT_UDIVI (SLJIT_OP0_BASE + 6) ++#define SLJIT_IUDIVI (SLJIT_UDIVI | SLJIT_INT_OP) ++/* Flags: I - (may destroy flags) ++ Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1. ++ The result is placed into SLJIT_R0. SLJIT_R1 preserves its value. ++ Note: if SLJIT_R1 is 0, the behaviour is undefined. ++ Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00), ++ the behaviour is undefined. ++ Note: SLJIT_SDIV is single precision divide. */ ++#define SLJIT_SDIVI (SLJIT_OP0_BASE + 7) ++#define SLJIT_ISDIVI (SLJIT_SDIVI | SLJIT_INT_OP) + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op); + +@@ -851,34 +869,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler + sljit_si src1, sljit_sw src1w, + sljit_si src2, sljit_sw src2w); + +-/* The following function is a helper function for sljit_emit_op_custom. +- It returns with the real machine register index ( >=0 ) of any SLJIT_R, +- SLJIT_S and SLJIT_SP registers. +- +- Note: it returns with -1 for virtual registers (only on x86-32). */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg); +- +-/* The following function is a helper function for sljit_emit_op_custom. +- It returns with the real machine register index of any SLJIT_FLOAT register. +- +- Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg); +- +-/* Any instruction can be inserted into the instruction stream by +- sljit_emit_op_custom. It has a similar purpose as inline assembly. +- The size parameter must match to the instruction size of the target +- architecture: +- +- x86: 0 < size <= 15. The instruction argument can be byte aligned. +- Thumb2: if size == 2, the instruction argument must be 2 byte aligned. +- if size == 4, the instruction argument must be 4 byte aligned. +- Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */ +- +-SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, +- void *instruction, sljit_si size); +- + /* Returns with non-zero if fpu is available. */ + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_is_fpu_available(void); +@@ -1196,4 +1186,64 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct + + #endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */ + ++/* --------------------------------------------------------------------- */ ++/* CPU specific functions */ ++/* --------------------------------------------------------------------- */ ++ ++/* The following function is a helper function for sljit_emit_op_custom. ++ It returns with the real machine register index ( >=0 ) of any SLJIT_R, ++ SLJIT_S and SLJIT_SP registers. ++ ++ Note: it returns with -1 for virtual registers (only on x86-32). */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg); ++ ++/* The following function is a helper function for sljit_emit_op_custom. ++ It returns with the real machine register index of any SLJIT_FLOAT register. ++ ++ Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_float_register_index(sljit_si reg); ++ ++/* Any instruction can be inserted into the instruction stream by ++ sljit_emit_op_custom. It has a similar purpose as inline assembly. ++ The size parameter must match to the instruction size of the target ++ architecture: ++ ++ x86: 0 < size <= 15. The instruction argument can be byte aligned. ++ Thumb2: if size == 2, the instruction argument must be 2 byte aligned. ++ if size == 4, the instruction argument must be 4 byte aligned. ++ Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, ++ void *instruction, sljit_si size); ++ ++#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) ++ ++/* Returns with non-zero if sse2 is available. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void); ++ ++/* Returns with non-zero if cmov instruction is available. */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_cmov_available(void); ++ ++/* Emit a conditional mov instruction on x86 CPUs. This instruction ++ moves src to destination, if the condition is satisfied. Unlike ++ other arithmetic instructions, destination must be a register. ++ Before such instructions are emitted, cmov support should be ++ checked by sljit_x86_is_cmov_available function. ++ type must be between SLJIT_EQUAL and SLJIT_S_ORDERED ++ dst_reg must be a valid register and it can be combined ++ with SLJIT_INT_OP to perform 32 bit arithmetic ++ Flags: I - (never set any flags) ++ */ ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler, ++ sljit_si type, ++ sljit_si dst_reg, ++ sljit_si src, sljit_sw srcw); ++ ++#endif ++ + #endif /* _SLJIT_LIR_H_ */ +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeARM_32.c b/ext/pcre/pcrelib/sljit/sljitNativeARM_32.c +index aca1d31..5cd4c71 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeARM_32.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeARM_32.c +@@ -1833,18 +1833,33 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + | (reg_map[SLJIT_R0] << 8) + | reg_map[TMP_REG1]); + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: +- if (compiler->scratches >= 3) ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); ++ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2, bad_register_mapping); ++ ++ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) { + FAIL_IF(push_inst(compiler, 0xe52d2008 /* str r2, [sp, #-8]! */)); ++ FAIL_IF(push_inst(compiler, 0xe58d1004 /* str r1, [sp, #4] */)); ++ } ++ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3)) ++ FAIL_IF(push_inst(compiler, 0xe52d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* str r1/r2, [sp, #-8]! */)); ++ + #if defined(__GNUC__) + FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, +- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); ++ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); + #else + #error "Software divmod functions are needed" + #endif +- if (compiler->scratches >= 3) +- return push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */); ++ ++ if ((op >= SLJIT_UDIVI) && (compiler->scratches >= 3)) { ++ FAIL_IF(push_inst(compiler, 0xe59d1004 /* ldr r1, [sp, #4] */)); ++ FAIL_IF(push_inst(compiler, 0xe49d2008 /* ldr r2, [sp], #8 */)); ++ } ++ else if ((op >= SLJIT_UDIVI) || (compiler->scratches >= 3)) ++ return push_inst(compiler, 0xe49d0008 | (op >= SLJIT_UDIVI ? 0x1000 : 0x2000) /* ldr r1/r2, [sp], #8 */); + return SLJIT_SUCCESS; + } + +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeARM_64.c b/ext/pcre/pcrelib/sljit/sljitNativeARM_64.c +index b66455f..044a675 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeARM_64.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeARM_64.c +@@ -1087,14 +1087,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil + saved_regs_size += sizeof(sljit_sw); + } + local_size -= saved_regs_size + SLJIT_LOCALS_OFFSET; +- FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); ++ if (saved_regs_size > 0) ++ FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); + } + + tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; + prev = -1; + for (i = SLJIT_S0; i >= tmp; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1104,7 +1110,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil + + for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, STRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1112,8 +1123,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil + prev = -1; + } + +- if (prev != -1) +- FAIL_IF(push_inst(compiler, STRI | RT(prev) | RN(TMP_SP) | (offs >> 5))); ++ SLJIT_ASSERT(prev == -1); + + if (compiler->local_size > (63 * sizeof(sljit_sw))) { + /* The local_size is already adjusted by the saved registers. */ +@@ -1188,7 +1198,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi + prev = -1; + for (i = SLJIT_S0; i >= tmp; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1198,7 +1213,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi + + for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { + if (prev == -1) { +- prev = i; ++ if (!(offs & (1 << 15))) { ++ prev = i; ++ continue; ++ } ++ FAIL_IF(push_inst(compiler, LDRI | RT(i) | RN(TMP_SP) | (offs >> 5))); ++ offs += 1 << 15; + continue; + } + FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(TMP_SP) | offs)); +@@ -1206,13 +1226,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi + prev = -1; + } + +- if (prev != -1) +- FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(TMP_SP) | (offs >> 5))); ++ SLJIT_ASSERT(prev == -1); + + if (compiler->local_size <= (63 * sizeof(sljit_sw))) { + FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR) + | RN(TMP_SP) | (((local_size >> 3) & 0x7f) << 15))); +- } else { ++ } else if (saved_regs_size > 0) { + FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); + } + +@@ -1242,12 +1261,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); + FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); + return push_inst(compiler, (op == SLJIT_LUMUL ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: + FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0))); +- FAIL_IF(push_inst(compiler, ((op == SLJIT_LUDIV ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, ((op == SLJIT_UDIVMOD ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1))); + FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO))); + return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1)); ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ return push_inst(compiler, ((op == SLJIT_UDIVI ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)); + } + + return SLJIT_SUCCESS; +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeARM_T2_32.c b/ext/pcre/pcrelib/sljit/sljitNativeARM_T2_32.c +index 6e38cec..f9803f5 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeARM_T2_32.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeARM_T2_32.c +@@ -1239,6 +1239,9 @@ extern int __aeabi_idivmod(int numerator, int denominator); + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) + { ++ sljit_sw saved_reg_list[3]; ++ sljit_sw saved_reg_count; ++ + CHECK_ERROR(); + CHECK(check_sljit_emit_op0(compiler, op)); + +@@ -1255,24 +1258,53 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + | (reg_map[SLJIT_R0] << 12) + | (reg_map[SLJIT_R0] << 16) + | reg_map[SLJIT_R1]); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: +- if (compiler->scratches >= 4) { +- FAIL_IF(push_inst32(compiler, 0xf84d2d04 /* str r2, [sp, #-4]! */)); +- FAIL_IF(push_inst32(compiler, 0xf84dcd04 /* str ip, [sp, #-4]! */)); +- } else if (compiler->scratches >= 3) +- FAIL_IF(push_inst32(compiler, 0xf84d2d08 /* str r2, [sp, #-8]! */)); ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); ++ SLJIT_COMPILE_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 12, bad_register_mapping); ++ ++ saved_reg_count = 0; ++ if (compiler->scratches >= 4) ++ saved_reg_list[saved_reg_count++] = 12; ++ if (compiler->scratches >= 3) ++ saved_reg_list[saved_reg_count++] = 2; ++ if (op >= SLJIT_UDIVI) ++ saved_reg_list[saved_reg_count++] = 1; ++ ++ if (saved_reg_count > 0) { ++ FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8) ++ | (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */)); ++ if (saved_reg_count >= 2) { ++ SLJIT_ASSERT(saved_reg_list[1] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */)); ++ } ++ if (saved_reg_count >= 3) { ++ SLJIT_ASSERT(saved_reg_list[2] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */)); ++ } ++ } ++ + #if defined(__GNUC__) + FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM, +- (op == SLJIT_LUDIV ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); ++ ((op | 0x2) == SLJIT_UDIVI ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod)))); + #else + #error "Software divmod functions are needed" + #endif +- if (compiler->scratches >= 4) { +- FAIL_IF(push_inst32(compiler, 0xf85dcb04 /* ldr ip, [sp], #4 */)); +- return push_inst32(compiler, 0xf85d2b04 /* ldr r2, [sp], #4 */); +- } else if (compiler->scratches >= 3) +- return push_inst32(compiler, 0xf85d2b08 /* ldr r2, [sp], #8 */); ++ ++ if (saved_reg_count > 0) { ++ if (saved_reg_count >= 3) { ++ SLJIT_ASSERT(saved_reg_list[2] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */)); ++ } ++ if (saved_reg_count >= 2) { ++ SLJIT_ASSERT(saved_reg_list[1] < 8); ++ FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */)); ++ } ++ return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8) ++ | (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */); ++ } + return SLJIT_SUCCESS; + } + +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeMIPS_common.c b/ext/pcre/pcrelib/sljit/sljitNativeMIPS_common.c +index 3e2c9f0..cf3535f 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeMIPS_common.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeMIPS_common.c +@@ -1053,8 +1053,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + #endif + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); + return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + #if !(defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1) + FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); + FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS)); +@@ -1062,15 +1065,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + + #if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) + if (int_op) +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + #else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS)); + #endif + + FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0))); +- return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); ++ return (op >= SLJIT_UDIVI) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1)); + } + + return SLJIT_SUCCESS; +diff --git a/ext/pcre/pcrelib/sljit/sljitNativePPC_common.c b/ext/pcre/pcrelib/sljit/sljitNativePPC_common.c +index 08d5356..b6a043f 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativePPC_common.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativePPC_common.c +@@ -1267,22 +1267,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); + return push_inst(compiler, (op == SLJIT_LUMUL ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1)); + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: + FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0))); + #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) +- if (int_op) { +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); +- } else { +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVDU : DIVD) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); +- } +- return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1)); ++ FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_UDIVMOD ? DIVWU : DIVW) : (op == SLJIT_UDIVMOD ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); + #else +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? DIVWU : DIVW) | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1))); ++ FAIL_IF(push_inst(compiler, (op == SLJIT_UDIVMOD ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1))); + FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1))); ++#endif + return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1)); ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) ++ return push_inst(compiler, (int_op ? (op == SLJIT_UDIVI ? DIVWU : DIVW) : (op == SLJIT_UDIVI ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); ++#else ++ return push_inst(compiler, (op == SLJIT_UDIVI ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)); + #endif + } + +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeSPARC_common.c b/ext/pcre/pcrelib/sljit/sljitNativeSPARC_common.c +index 0b1927a..327c426 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeSPARC_common.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeSPARC_common.c +@@ -777,20 +777,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + #else + #error "Implementation required" + #endif +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + #if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) +- if (op == SLJIT_LUDIV) ++ if ((op | 0x2) == SLJIT_UDIVI) + FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS)); + else { + FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1))); + FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS)); + } +- FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2))); +- FAIL_IF(push_inst(compiler, (op == SLJIT_LUDIV ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0))); ++ if (op <= SLJIT_SDIVMOD) ++ FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2))); ++ FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_UDIVI ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0))); ++ if (op >= SLJIT_UDIVI) ++ return SLJIT_SUCCESS; + FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1))); +- FAIL_IF(push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1))); +- return SLJIT_SUCCESS; ++ return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1)); + #else + #error "Implementation required" + #endif +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeTILEGX_64.c b/ext/pcre/pcrelib/sljit/sljitNativeTILEGX_64.c +index 1d6aa5a..4d40392f 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeTILEGX_64.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeTILEGX_64.c +@@ -35,21 +35,21 @@ + #define SIMM_16BIT_MIN (-0x8000) + #define SIMM_17BIT_MAX (0xffff) + #define SIMM_17BIT_MIN (-0x10000) +-#define SIMM_32BIT_MIN (-0x80000000) + #define SIMM_32BIT_MAX (0x7fffffff) +-#define SIMM_48BIT_MIN (0x800000000000L) ++#define SIMM_32BIT_MIN (-0x7fffffff - 1) + #define SIMM_48BIT_MAX (0x7fffffff0000L) ++#define SIMM_48BIT_MIN (-0x800000000000L) + #define IMM16(imm) ((imm) & 0xffff) + + #define UIMM_16BIT_MAX (0xffff) + +-#define TMP_REG1 (SLJIT_NO_REGISTERS + 1) +-#define TMP_REG2 (SLJIT_NO_REGISTERS + 2) +-#define TMP_REG3 (SLJIT_NO_REGISTERS + 3) +-#define ADDR_TMP (SLJIT_NO_REGISTERS + 4) ++#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2) ++#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3) ++#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4) ++#define ADDR_TMP (SLJIT_NUMBER_OF_REGISTERS + 5) + #define PIC_ADDR_REG TMP_REG2 + +-static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { ++static SLJIT_CONST sljit_ub reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = { + 63, 0, 1, 2, 3, 4, 30, 31, 32, 33, 34, 54, 5, 16, 6, 7 + }; + +@@ -58,11 +58,6 @@ static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 5] = { + #define TMP_REG2_mapped 16 + #define TMP_REG3_mapped 6 + #define ADDR_TMP_mapped 7 +-#define SLJIT_SAVED_REG1_mapped 30 +-#define SLJIT_SAVED_REG2_mapped 31 +-#define SLJIT_SAVED_REG3_mapped 32 +-#define SLJIT_SAVED_EREG1_mapped 33 +-#define SLJIT_SAVED_EREG2_mapped 34 + + /* Flags are keept in volatile registers. */ + #define EQUAL_FLAG 8 +@@ -399,6 +394,9 @@ static sljit_si push_inst(struct sljit_compiler *compiler, sljit_ins ins) + #define SUB(dst, srca, srcb) \ + push_3_buffer(compiler, TILEGX_OPC_SUB, dst, srca, srcb, __LINE__) + ++#define MUL(dst, srca, srcb) \ ++ push_3_buffer(compiler, TILEGX_OPC_MULX, dst, srca, srcb, __LINE__) ++ + #define NOR(dst, srca, srcb) \ + push_3_buffer(compiler, TILEGX_OPC_NOR, dst, srca, srcb, __LINE__) + +@@ -547,8 +545,8 @@ const struct Format* compute_format() + + const struct Format* match = NULL; + const struct Format *b = NULL; +- unsigned int i = 0; +- for (i; i < sizeof formats / sizeof formats[0]; i++) { ++ unsigned int i; ++ for (i = 0; i < sizeof formats / sizeof formats[0]; i++) { + b = &formats[i]; + if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) { + match = b; +@@ -625,7 +623,6 @@ tilegx_bundle_bits get_bundle_bit(struct jit_instr *inst) + + static sljit_si update_buffer(struct sljit_compiler *compiler) + { +- int count; + int i; + int orig_index = inst_buf_index; + struct jit_instr inst0 = inst_buf[0]; +@@ -738,8 +735,10 @@ static sljit_si update_buffer(struct sljit_compiler *compiler) + + static sljit_si flush_buffer(struct sljit_compiler *compiler) + { +- while (inst_buf_index != 0) +- update_buffer(compiler); ++ while (inst_buf_index != 0) { ++ FAIL_IF(update_buffer(compiler)); ++ } ++ return SLJIT_SUCCESS; + } + + static sljit_si push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line) +@@ -787,6 +786,7 @@ static sljit_si push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic o + case TILEGX_OPC_ADD: + case TILEGX_OPC_AND: + case TILEGX_OPC_SUB: ++ case TILEGX_OPC_MULX: + case TILEGX_OPC_OR: + case TILEGX_OPC_XOR: + case TILEGX_OPC_NOR: +@@ -905,7 +905,6 @@ static SLJIT_INLINE sljit_ins * detect_jump_type(struct sljit_jump *jump, sljit_ + sljit_sw diff; + sljit_uw target_addr; + sljit_ins *inst; +- sljit_ins saved_inst; + + if (jump->flags & SLJIT_REWRITABLE_JUMP) + return code_ptr; +@@ -1009,7 +1008,7 @@ SLJIT_API_FUNC_ATTRIBUTE void * sljit_generate_code(struct sljit_compiler *compi + struct sljit_const *const_; + + CHECK_ERROR_PTR(); +- check_sljit_generate_code(compiler); ++ CHECK_PTR(check_sljit_generate_code(compiler)); + reverse_buf(compiler); + + code = (sljit_ins *)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins)); +@@ -1178,13 +1177,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil + sljit_si fscratches, sljit_si fsaveds, sljit_si local_size) + { + sljit_ins base; +- sljit_ins bundle = 0; +- ++ sljit_si i, tmp; ++ + CHECK_ERROR(); +- check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); ++ CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); + set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); + +- local_size += (saveds + 1) * sizeof(sljit_sw); ++ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); + local_size = (local_size + 7) & ~7; + compiler->local_size = local_size; + +@@ -1200,56 +1199,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil + local_size = 0; + } + ++ /* Save the return address. */ + FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8)); + FAIL_IF(ST_ADD(ADDR_TMP_mapped, RA, -8)); + +- if (saveds >= 1) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG1_mapped, -8)); +- +- if (saveds >= 2) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG2_mapped, -8)); +- +- if (saveds >= 3) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_REG3_mapped, -8)); +- +- if (saveds >= 4) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG1_mapped, -8)); +- +- if (saveds >= 5) +- FAIL_IF(ST_ADD(ADDR_TMP_mapped, SLJIT_SAVED_EREG2_mapped, -8)); +- +- if (args >= 1) +- FAIL_IF(ADD(SLJIT_SAVED_REG1_mapped, 0, ZERO)); ++ /* Save the S registers. */ ++ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; ++ for (i = SLJIT_S0; i >= tmp; i--) { ++ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8)); ++ } + +- if (args >= 2) +- FAIL_IF(ADD(SLJIT_SAVED_REG2_mapped, 1, ZERO)); ++ /* Save the R registers that need to be reserved. */ ++ for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { ++ FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8)); ++ } + +- if (args >= 3) +- FAIL_IF(ADD(SLJIT_SAVED_REG3_mapped, 2, ZERO)); ++ /* Move the arguments to S registers. */ ++ for (i = 0; i < args; i++) { ++ FAIL_IF(ADD(reg_map[SLJIT_S0 - i], i, ZERO)); ++ } + + return SLJIT_SUCCESS; + } + +-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_context(struct sljit_compiler *compiler, ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler, + sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds, + sljit_si fscratches, sljit_si fsaveds, sljit_si local_size) + { +- CHECK_ERROR_VOID(); +- check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); ++ CHECK_ERROR(); ++ CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size)); + set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size); + +- local_size += (saveds + 1) * sizeof(sljit_sw); ++ local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1); + compiler->local_size = (local_size + 7) & ~7; ++ ++ return SLJIT_SUCCESS; + } + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw) + { + sljit_si local_size; + sljit_ins base; +- int addr_initialized = 0; ++ sljit_si i, tmp; ++ sljit_si saveds; + + CHECK_ERROR(); +- check_sljit_emit_return(compiler, op, src, srcw); ++ CHECK(check_sljit_emit_return(compiler, op, src, srcw)); + + FAIL_IF(emit_mov_before_return(compiler, op, src, srcw)); + +@@ -1263,50 +1258,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi + local_size = 0; + } + ++ /* Restore the return address. */ + FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8)); +- FAIL_IF(LD(RA, ADDR_TMP_mapped)); +- +- if (compiler->saveds >= 5) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 48)); +- addr_initialized = 1; ++ FAIL_IF(LD_ADD(RA, ADDR_TMP_mapped, -8)); + +- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG2_mapped, ADDR_TMP_mapped, 8)); ++ /* Restore the S registers. */ ++ saveds = compiler->saveds; ++ tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; ++ for (i = SLJIT_S0; i >= tmp; i--) { ++ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8)); + } + +- if (compiler->saveds >= 4) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 40)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_EREG1_mapped, ADDR_TMP_mapped, 8)); +- } +- +- if (compiler->saveds >= 3) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 32)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG3_mapped, ADDR_TMP_mapped, 8)); +- } +- +- if (compiler->saveds >= 2) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 24)); +- addr_initialized = 1; +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG2_mapped, ADDR_TMP_mapped, 8)); +- } +- +- if (compiler->saveds >= 1) { +- if (addr_initialized == 0) { +- FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 16)); +- /* addr_initialized = 1; no need to initialize as it's the last one. */ +- } +- +- FAIL_IF(LD_ADD(SLJIT_SAVED_REG1_mapped, ADDR_TMP_mapped, 8)); ++ /* Restore the R registers that need to be reserved. */ ++ for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) { ++ FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8)); + } + + if (compiler->local_size <= SIMM_16BIT_MAX) +@@ -1585,7 +1550,7 @@ static SLJIT_INLINE sljit_si emit_op_mem2(struct sljit_compiler *compiler, sljit + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw) + { + CHECK_ERROR(); +- check_sljit_emit_fast_enter(compiler, dst, dstw); ++ CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + /* For UNUSED dst. Uncommon, but possible. */ +@@ -1602,7 +1567,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *c + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw) + { + CHECK_ERROR(); +- check_sljit_emit_fast_return(compiler, src, srcw); ++ CHECK(check_sljit_emit_fast_return(compiler, src, srcw)); + ADJUST_LOCAL_OFFSET(src, srcw); + + if (FAST_IS_REG(src)) +@@ -1636,9 +1601,11 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + if (op == SLJIT_MOV_SI) + return BFEXTS(reg_map[dst], reg_map[src2], 0, 31); + +- return BFEXTU(reg_map[dst], reg_map[src2], 0, 31); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ return BFEXTU(reg_map[dst], reg_map[src2], 0, 31); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1650,8 +1617,10 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + return BFEXTS(reg_map[dst], reg_map[src2], 0, 7); + + return BFEXTU(reg_map[dst], reg_map[src2], 0, 7); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1663,8 +1632,10 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + return BFEXTS(reg_map[dst], reg_map[src2], 0, 15); + + return BFEXTU(reg_map[dst], reg_map[src2], 0, 15); +- } else if (dst != src2) +- SLJIT_ASSERT_STOP(); ++ } else if (dst != src2) { ++ SLJIT_ASSERT(src2 == 0); ++ return ADD(reg_map[dst], reg_map[src2], ZERO); ++ } + + return SLJIT_SUCCESS; + +@@ -1811,7 +1782,6 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + else { + /* Rare ocasion. */ + FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO)); +- + overflow_ra = TMP_EREG2; + } + } +@@ -1903,6 +1873,17 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + + return SLJIT_SUCCESS; + ++ case SLJIT_MUL: ++ if (flags & SRC2_IMM) { ++ FAIL_IF(load_immediate(compiler, TMP_REG2_mapped, src2)); ++ src2 = TMP_REG2; ++ flags &= ~SRC2_IMM; ++ } ++ ++ FAIL_IF(MUL(reg_map[dst], reg_map[src1], reg_map[src2])); ++ ++ return SLJIT_SUCCESS; ++ + #define EMIT_LOGICAL(op_imm, op_norm) \ + if (flags & SRC2_IMM) { \ + FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2)); \ +@@ -1950,8 +1931,8 @@ static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, slj + } else { \ + if (op & SLJIT_SET_E) \ + FAIL_IF(push_3_buffer( \ +- compiler, op_imm, reg_map[dst], reg_map[src1], \ +- src2 & 0x3F, __LINE__)); \ ++ compiler, op_norm, EQUAL_FLAG, reg_map[src1], \ ++ reg_map[src2], __LINE__)); \ + if (CHECK_FLAGS(SLJIT_SET_E)) \ + FAIL_IF(push_3_buffer( \ + compiler, op_norm, reg_map[dst], reg_map[src1], \ +@@ -2105,66 +2086,61 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com + { + sljit_si sugg_dst_ar, dst_ar; + sljit_si flags = GET_ALL_FLAGS(op); ++ sljit_si mem_type = (op & SLJIT_INT_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA; + + CHECK_ERROR(); +- check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type); ++ CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + if (dst == SLJIT_UNUSED) + return SLJIT_SUCCESS; + + op = GET_OPCODE(op); ++ if (op == SLJIT_MOV_SI || op == SLJIT_MOV_UI) ++ mem_type = INT_DATA | SIGNED_DATA; + sugg_dst_ar = reg_map[(op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2]; + + compiler->cache_arg = 0; + compiler->cache_argw = 0; + if (op >= SLJIT_ADD && (src & SLJIT_MEM)) { + ADJUST_LOCAL_OFFSET(src, srcw); +- FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw)); ++ FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw)); + src = TMP_REG1; + srcw = 0; + } + +- switch (type) { +- case SLJIT_C_EQUAL: +- case SLJIT_C_NOT_EQUAL: ++ switch (type & 0xff) { ++ case SLJIT_EQUAL: ++ case SLJIT_NOT_EQUAL: + FAIL_IF(CMPLTUI(sugg_dst_ar, EQUAL_FLAG, 1)); + dst_ar = sugg_dst_ar; + break; +- case SLJIT_C_LESS: +- case SLJIT_C_GREATER_EQUAL: +- case SLJIT_C_FLOAT_LESS: +- case SLJIT_C_FLOAT_GREATER_EQUAL: ++ case SLJIT_LESS: ++ case SLJIT_GREATER_EQUAL: + dst_ar = ULESS_FLAG; + break; +- case SLJIT_C_GREATER: +- case SLJIT_C_LESS_EQUAL: +- case SLJIT_C_FLOAT_GREATER: +- case SLJIT_C_FLOAT_LESS_EQUAL: ++ case SLJIT_GREATER: ++ case SLJIT_LESS_EQUAL: + dst_ar = UGREATER_FLAG; + break; +- case SLJIT_C_SIG_LESS: +- case SLJIT_C_SIG_GREATER_EQUAL: ++ case SLJIT_SIG_LESS: ++ case SLJIT_SIG_GREATER_EQUAL: + dst_ar = LESS_FLAG; + break; +- case SLJIT_C_SIG_GREATER: +- case SLJIT_C_SIG_LESS_EQUAL: ++ case SLJIT_SIG_GREATER: ++ case SLJIT_SIG_LESS_EQUAL: + dst_ar = GREATER_FLAG; + break; +- case SLJIT_C_OVERFLOW: +- case SLJIT_C_NOT_OVERFLOW: ++ case SLJIT_OVERFLOW: ++ case SLJIT_NOT_OVERFLOW: + dst_ar = OVERFLOW_FLAG; + break; +- case SLJIT_C_MUL_OVERFLOW: +- case SLJIT_C_MUL_NOT_OVERFLOW: ++ case SLJIT_MUL_OVERFLOW: ++ case SLJIT_MUL_NOT_OVERFLOW: + FAIL_IF(CMPLTUI(sugg_dst_ar, OVERFLOW_FLAG, 1)); + dst_ar = sugg_dst_ar; + type ^= 0x1; /* Flip type bit for the XORI below. */ + break; +- case SLJIT_C_FLOAT_EQUAL: +- case SLJIT_C_FLOAT_NOT_EQUAL: +- dst_ar = EQUAL_FLAG; +- break; + + default: + SLJIT_ASSERT_STOP(); +@@ -2180,11 +2156,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com + if (op >= SLJIT_ADD) { + if (TMP_REG2_mapped != dst_ar) + FAIL_IF(ADD(TMP_REG2_mapped, dst_ar, ZERO)); +- return emit_op(compiler, op | flags, CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0); ++ return emit_op(compiler, op | flags, mem_type | CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0); + } + + if (dst & SLJIT_MEM) +- return emit_op_mem(compiler, WORD_DATA, dst_ar, dst, dstw); ++ return emit_op_mem(compiler, mem_type, dst_ar, dst, dstw); + + if (sugg_dst_ar != dst_ar) + return ADD(sugg_dst_ar, dst_ar, ZERO); +@@ -2194,7 +2170,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_flags(struct sljit_compiler *com + + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler, sljit_si op) { + CHECK_ERROR(); +- check_sljit_emit_op0(compiler, op); ++ CHECK(check_sljit_emit_op0(compiler, op)); + + op = GET_OPCODE(op); + switch (op) { +@@ -2204,10 +2180,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + case SLJIT_BREAKPOINT: + return PI(BPT); + +- case SLJIT_UMUL: +- case SLJIT_SMUL: +- case SLJIT_UDIV: +- case SLJIT_SDIV: ++ case SLJIT_LUMUL: ++ case SLJIT_LSMUL: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: + SLJIT_ASSERT_STOP(); + } + +@@ -2217,7 +2193,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src, sljit_sw srcw) + { + CHECK_ERROR(); +- check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw); ++ CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw)); + ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src, srcw); + +@@ -2273,7 +2249,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler + return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw); + + case SLJIT_CLZ: +- return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw); ++ return emit_op(compiler, op, (op & SLJIT_INT_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw); + } + + return SLJIT_SUCCESS; +@@ -2282,7 +2258,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op1(struct sljit_compiler *compiler + SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op2(struct sljit_compiler *compiler, sljit_si op, sljit_si dst, sljit_sw dstw, sljit_si src1, sljit_sw src1w, sljit_si src2, sljit_sw src2w) + { + CHECK_ERROR(); +- check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w); ++ CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w)); + ADJUST_LOCAL_OFFSET(dst, dstw); + ADJUST_LOCAL_OFFSET(src1, src1w); + ADJUST_LOCAL_OFFSET(src2, src2w); +@@ -2325,7 +2301,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label * sljit_emit_label(struct sljit_comp + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_label(compiler); ++ CHECK_PTR(check_sljit_emit_label(compiler)); + + if (compiler->last_label && compiler->last_label->size == compiler->size) + return compiler->last_label; +@@ -2344,7 +2320,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compil + flush_buffer(compiler); + + CHECK_ERROR(); +- check_sljit_emit_ijump(compiler, type, src, srcw); ++ CHECK(check_sljit_emit_ijump(compiler, type, src, srcw)); + ADJUST_LOCAL_OFFSET(src, srcw); + + if (FAST_IS_REG(src)) { +@@ -2404,8 +2380,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_ijump(struct sljit_compiler *compil + + return SLJIT_SUCCESS; + +- } else if (src & SLJIT_MEM) ++ } else if (src & SLJIT_MEM) { + FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw)); ++ flush_buffer(compiler); ++ } + + FAIL_IF(JR_SOLO(reg_map[src_r])); + +@@ -2432,7 +2410,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_jump(compiler, type); ++ CHECK_PTR(check_sljit_emit_jump(compiler, type)); + + jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump)); + PTR_FAIL_IF(!jump); +@@ -2440,48 +2418,42 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compil + type &= 0xff; + + switch (type) { +- case SLJIT_C_EQUAL: +- case SLJIT_C_FLOAT_NOT_EQUAL: ++ case SLJIT_EQUAL: + BR_NZ(EQUAL_FLAG); + break; +- case SLJIT_C_NOT_EQUAL: +- case SLJIT_C_FLOAT_EQUAL: ++ case SLJIT_NOT_EQUAL: + BR_Z(EQUAL_FLAG); + break; +- case SLJIT_C_LESS: +- case SLJIT_C_FLOAT_LESS: ++ case SLJIT_LESS: + BR_Z(ULESS_FLAG); + break; +- case SLJIT_C_GREATER_EQUAL: +- case SLJIT_C_FLOAT_GREATER_EQUAL: ++ case SLJIT_GREATER_EQUAL: + BR_NZ(ULESS_FLAG); + break; +- case SLJIT_C_GREATER: +- case SLJIT_C_FLOAT_GREATER: ++ case SLJIT_GREATER: + BR_Z(UGREATER_FLAG); + break; +- case SLJIT_C_LESS_EQUAL: +- case SLJIT_C_FLOAT_LESS_EQUAL: ++ case SLJIT_LESS_EQUAL: + BR_NZ(UGREATER_FLAG); + break; +- case SLJIT_C_SIG_LESS: ++ case SLJIT_SIG_LESS: + BR_Z(LESS_FLAG); + break; +- case SLJIT_C_SIG_GREATER_EQUAL: ++ case SLJIT_SIG_GREATER_EQUAL: + BR_NZ(LESS_FLAG); + break; +- case SLJIT_C_SIG_GREATER: ++ case SLJIT_SIG_GREATER: + BR_Z(GREATER_FLAG); + break; +- case SLJIT_C_SIG_LESS_EQUAL: ++ case SLJIT_SIG_LESS_EQUAL: + BR_NZ(GREATER_FLAG); + break; +- case SLJIT_C_OVERFLOW: +- case SLJIT_C_MUL_OVERFLOW: ++ case SLJIT_OVERFLOW: ++ case SLJIT_MUL_OVERFLOW: + BR_Z(OVERFLOW_FLAG); + break; +- case SLJIT_C_NOT_OVERFLOW: +- case SLJIT_C_MUL_NOT_OVERFLOW: ++ case SLJIT_NOT_OVERFLOW: ++ case SLJIT_MUL_NOT_OVERFLOW: + BR_NZ(OVERFLOW_FLAG); + break; + default: +@@ -2536,7 +2508,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_comp + flush_buffer(compiler); + + CHECK_ERROR_PTR(); +- check_sljit_emit_const(compiler, dst, dstw, init_value); ++ CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value)); + ADJUST_LOCAL_OFFSET(dst, dstw); + + const_ = (struct sljit_const *)ensure_abuf(compiler, sizeof(struct sljit_const)); +@@ -2572,3 +2544,18 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta + inst[3] = (inst[3] & ~(0xFFFFL << 43)) | ((new_constant & 0xFFFFL) << 43); + SLJIT_CACHE_FLUSH(inst, inst + 4); + } ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_get_register_index(sljit_si reg) ++{ ++ CHECK_REG_INDEX(check_sljit_get_register_index(reg)); ++ return reg_map[reg]; ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op_custom(struct sljit_compiler *compiler, ++ void *instruction, sljit_si size) ++{ ++ CHECK_ERROR(); ++ CHECK(check_sljit_emit_op_custom(compiler, instruction, size)); ++ return SLJIT_ERR_UNSUPPORTED; ++} ++ +diff --git a/ext/pcre/pcrelib/sljit/sljitNativeX86_common.c b/ext/pcre/pcrelib/sljit/sljitNativeX86_common.c +index 22a163f..416c15a 100644 +--- a/ext/pcre/pcrelib/sljit/sljitNativeX86_common.c ++++ b/ext/pcre/pcrelib/sljit/sljitNativeX86_common.c +@@ -273,7 +273,9 @@ static sljit_si cpu_has_sse2 = -1; + #endif + static sljit_si cpu_has_cmov = -1; + +-#if defined(_MSC_VER) && _MSC_VER >= 1400 ++#ifdef _WIN32_WCE ++#include <cmnintrin.h> ++#elif defined(_MSC_VER) && _MSC_VER >= 1400 + #include <intrin.h> + #endif + +@@ -742,8 +744,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + break; + case SLJIT_LUMUL: + case SLJIT_LSMUL: +- case SLJIT_LUDIV: +- case SLJIT_LSDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_SDIVMOD: ++ case SLJIT_UDIVI: ++ case SLJIT_SDIVI: + compiler->flags_saved = 0; + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + #ifdef _WIN64 +@@ -761,9 +765,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + #endif + compiler->mode32 = op & SLJIT_INT_OP; + #endif ++ SLJIT_COMPILE_ASSERT((SLJIT_UDIVMOD & 0x2) == 0 && SLJIT_UDIVI - 0x2 == SLJIT_UDIVMOD, bad_div_opcode_assignments); + + op = GET_OPCODE(op); +- if (op == SLJIT_LUDIV) { ++ if ((op | 0x2) == SLJIT_UDIVI) { + #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); + inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0); +@@ -774,7 +779,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + *inst = XOR_r_rm; + } + +- if (op == SLJIT_LSDIV) { ++ if ((op | 0x2) == SLJIT_SDIVI) { + #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0); + #endif +@@ -805,10 +810,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + FAIL_IF(!inst); + INC_SIZE(2); + *inst++ = GROUP_F7; +- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); ++ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]); + #else + #ifdef _WIN64 +- size = (!compiler->mode32 || op >= SLJIT_LUDIV) ? 3 : 2; ++ size = (!compiler->mode32 || op >= SLJIT_UDIVMOD) ? 3 : 2; + #else + size = (!compiler->mode32) ? 3 : 2; + #endif +@@ -817,11 +822,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + INC_SIZE(size); + #ifdef _WIN64 + if (!compiler->mode32) +- *inst++ = REX_W | ((op >= SLJIT_LUDIV) ? REX_B : 0); +- else if (op >= SLJIT_LUDIV) ++ *inst++ = REX_W | ((op >= SLJIT_UDIVMOD) ? REX_B : 0); ++ else if (op >= SLJIT_UDIVMOD) + *inst++ = REX_B; + *inst++ = GROUP_F7; +- *inst = MOD_REG | ((op >= SLJIT_LUDIV) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]); ++ *inst = MOD_REG | ((op >= SLJIT_UDIVMOD) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]); + #else + if (!compiler->mode32) + *inst++ = REX_W; +@@ -836,15 +841,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_op0(struct sljit_compiler *compiler + case SLJIT_LSMUL: + *inst |= IMUL; + break; +- case SLJIT_LUDIV: ++ case SLJIT_UDIVMOD: ++ case SLJIT_UDIVI: + *inst |= DIV; + break; +- case SLJIT_LSDIV: ++ case SLJIT_SDIVMOD: ++ case SLJIT_SDIVI: + *inst |= IDIV; + break; + } + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) +- EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); ++ if (op <= SLJIT_SDIVMOD) ++ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); ++#else ++ if (op >= SLJIT_UDIVI) ++ EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0); + #endif + break; + } +@@ -1905,60 +1916,62 @@ static sljit_si emit_test_binary(struct sljit_compiler *compiler, + return SLJIT_SUCCESS; + } + +- if (FAST_IS_REG(src1)) { ++ if (!(src1 & SLJIT_IMM)) { + if (src2 & SLJIT_IMM) { + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (IS_HALFWORD(src2w) || compiler->mode32) { +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); + FAIL_IF(!inst); + *inst = GROUP_F7; + } + else { + FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w)); +- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = TEST_rm_r; + } + #else +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w); + FAIL_IF(!inst); + *inst = GROUP_F7; + #endif ++ return SLJIT_SUCCESS; + } +- else { ++ else if (FAST_IS_REG(src1)) { + inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; ++ return SLJIT_SUCCESS; + } +- return SLJIT_SUCCESS; + } + +- if (FAST_IS_REG(src2)) { ++ if (!(src2 & SLJIT_IMM)) { + if (src1 & SLJIT_IMM) { + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + if (IS_HALFWORD(src1w) || compiler->mode32) { +- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w); + FAIL_IF(!inst); + *inst = GROUP_F7; + } + else { + FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w)); +- inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, src2, src2w); + FAIL_IF(!inst); + *inst = TEST_rm_r; + } + #else +- inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, 0); ++ inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, src2w); + FAIL_IF(!inst); + *inst = GROUP_F7; + #endif ++ return SLJIT_SUCCESS; + } +- else { ++ else if (FAST_IS_REG(src2)) { + inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w); + FAIL_IF(!inst); + *inst = TEST_rm_r; ++ return SLJIT_SUCCESS; + } +- return SLJIT_SUCCESS; + } + + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); +@@ -2923,3 +2936,69 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta + { + *(sljit_sw*)addr = new_constant; + } ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_sse2_available(void) ++{ ++#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) ++ if (cpu_has_sse2 == -1) ++ get_cpu_features(); ++ return cpu_has_sse2; ++#else ++ return 1; ++#endif ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_is_cmov_available(void) ++{ ++ if (cpu_has_cmov == -1) ++ get_cpu_features(); ++ return cpu_has_cmov; ++} ++ ++SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_x86_emit_cmov(struct sljit_compiler *compiler, ++ sljit_si type, ++ sljit_si dst_reg, ++ sljit_si src, sljit_sw srcw) ++{ ++ sljit_ub* inst; ++ ++ CHECK_ERROR(); ++#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) ++ CHECK_ARGUMENT(sljit_x86_is_cmov_available()); ++ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_INT_OP))); ++ CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_D_ORDERED); ++ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg & ~SLJIT_INT_OP)); ++ FUNCTION_CHECK_SRC(src, srcw); ++#endif ++#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) ++ if (SLJIT_UNLIKELY(!!compiler->verbose)) { ++ fprintf(compiler->verbose, " x86_cmov%s %s%s, ", ++ !(dst_reg & SLJIT_INT_OP) ? "" : ".i", ++ JUMP_PREFIX(type), jump_names[type & 0xff]); ++ sljit_verbose_reg(compiler, dst_reg & ~SLJIT_INT_OP); ++ fprintf(compiler->verbose, ", "); ++ sljit_verbose_param(compiler, src, srcw); ++ fprintf(compiler->verbose, "\n"); ++ } ++#endif ++ ++ ADJUST_LOCAL_OFFSET(src, srcw); ++ CHECK_EXTRA_REGS(src, srcw, (void)0); ++ ++#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) ++ compiler->mode32 = dst_reg & SLJIT_INT_OP; ++#endif ++ dst_reg &= ~SLJIT_INT_OP; ++ ++ if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { ++ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw); ++ src = TMP_REG1; ++ srcw = 0; ++ } ++ ++ inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw); ++ FAIL_IF(!inst); ++ *inst++ = GROUP_0F; ++ *inst = get_jump_code(type & 0xff) - 0x40; ++ return SLJIT_SUCCESS; ++} @@ -98,7 +98,7 @@ Summary: PHP scripting language for creating dynamic web sites Name: php Version: 5.4.45 -Release: 3%{?dist} +Release: 4%{?dist} # All files licensed under PHP version 3.01, except # Zend is licensed under Zend # TSRM is licensed under BSD @@ -162,6 +162,14 @@ Patch202: bug70755.patch Patch203: bug70728.patch Patch204: bug70741.patch Patch205: bug70661.patch +Patch206: bug71354.patch +Patch207: bug71335.patch +Patch208: bug71391.patch +Patch209: bug71323.patch +Patch210: bug71459.patch +Patch211: bug71039.patch +Patch212: bug71488.patch +Patch213: pcre838.patch # Fixes for tests # no_NO issue @@ -875,6 +883,14 @@ rm -f ext/json/utf8_to_utf16.* %patch203 -p1 -b .bug70728 %patch204 -p1 -b .bug70741 %patch205 -p1 -b .bug70661 +%patch206 -p1 -b .bug71354 +%patch207 -p1 -b .bug71335 +%patch208 -p1 -b .bug71391 +%patch209 -p1 -b .bug71323 +%patch210 -p1 -b .bug71459 +%patch211 -p1 -b .bug71039 +%patch212 -p1 -b .bug71488 +%patch213 -p1 -b .pcre838 # Fixes for tests %patch301 -p1 -b .datetests2 @@ -1531,7 +1547,7 @@ rm -rf $RPM_BUILD_ROOT%{_libdir}/php/modules/*.a \ rm -f README.{Zeus,QNX,CVS-RULES} -%pre common +%posttrans common cat << EOF ========================================================================== @@ -1764,6 +1780,17 @@ fi %changelog +* Tue Feb 16 2016 Remi Collet <remi@remirepo.net> 5.4.45-4 +- Fix #71354: phar, remove UMR when size is 0 +- Fix #71335: type confusion in WDDX packet deserialization +- Fix #71391: NULL pointer dereference in phar_tar_setupmetadata() +- Fix #71323: output of stream_get_meta_data can be falsified by its input +- Fix #71459: integer overflow in iptcembed() +- Fix #71039: exec functions ignore length but look for NULL termination +- Fix #71720: heap bufferover flow in escapeshell functions +- Fix #71488: Stack overflow when decompressing tar archives +- upgrade bundled PCRE to 8.38 + * Wed Jan 6 2016 Remi Collet <remi@fedoraproject.org> 5.4.45-3 - Fix #70755: fpm_log.c memory leak and buffer overflow - Fix #70728: Type Confusion Vulnerability in PHP_to_XMLRPC_worker |