[Pcre-svn] [426] code/trunk: Remove restrictions on pcre_exe…

Página Inicial
Delete this message
Autor: Subversion repository
Data:  
Para: pcre-svn
Assunto: [Pcre-svn] [426] code/trunk: Remove restrictions on pcre_exec() partial matching.
Revision: 426
          http://vcs.pcre.org/viewvc?view=rev&revision=426
Author:   ph10
Date:     2009-08-26 16:38:32 +0100 (Wed, 26 Aug 2009)


Log Message:
-----------
Remove restrictions on pcre_exec() partial matching.

Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/RunTest
    code/trunk/doc/pcre_exec.3
    code/trunk/doc/pcre_fullinfo.3
    code/trunk/doc/pcreapi.3
    code/trunk/doc/pcrecompat.3
    code/trunk/doc/pcrematching.3
    code/trunk/doc/pcrepartial.3
    code/trunk/doc/pcretest.1
    code/trunk/pcre_compile.c
    code/trunk/pcre_dfa_exec.c
    code/trunk/pcre_exec.c
    code/trunk/pcre_fullinfo.c
    code/trunk/pcre_internal.h
    code/trunk/pcretest.c
    code/trunk/testdata/testinput2
    code/trunk/testdata/testinput5
    code/trunk/testdata/testinput7
    code/trunk/testdata/testoutput2
    code/trunk/testdata/testoutput5
    code/trunk/testdata/testoutput6
    code/trunk/testdata/testoutput7


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/ChangeLog    2009-08-26 15:38:32 UTC (rev 426)
@@ -41,6 +41,16 @@
     unwanted data. My guess is that the person linked everything into his
     program rather than using a library. Anyway, it does no harm.


+8.  A pattern such as /\x{123}{2,2}+/8 was incorrectly compiled; the trigger
+    was a minimum greater than 1 for a wide character in a possessive 
+    repetition. Chaos could result. 
+    
+9.  The restrictions on what a pattern can contain when partial matching is
+    requested for pcre_exec() have been removed. All patterns can now be 
+    partially matched by this function. In addition, if there are at least two
+    slots in the offset vector, the offsets of the first-encountered partial
+    match are set in them when PCRE_ERROR_PARTIAL is returned.
+    


Version 7.9 11-Apr-09
---------------------

Modified: code/trunk/RunTest
===================================================================
--- code/trunk/RunTest    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/RunTest    2009-08-26 15:38:32 UTC (rev 426)
@@ -139,7 +139,7 @@
 # PCRE tests that are not Perl-compatible - API & error tests, mostly


 if [ $do2 = yes ] ; then
-  echo "Test 2: API and error handling (not Perl compatible)"
+  echo "Test 2: API, errors, and non-Perl stuff"
   $valgrind ./pcretest -q $testdata/testinput2 testtry
   if [ $? = 0 ] ; then
     $cf $testdata/testoutput2 testtry
@@ -216,7 +216,7 @@
 fi


 if [ $do5 = yes ] ; then
-  echo "Test 5: API and internals for UTF-8 support (not Perl compatible)"
+  echo "Test 5: API, internals, and non-Perl stuff for UTF-8 support"
   $valgrind ./pcretest -q $testdata/testinput5 testtry
   if [ $? = 0 ] ; then
     $cf $testdata/testoutput5 testtry


Modified: code/trunk/doc/pcre_exec.3
===================================================================
--- code/trunk/doc/pcre_exec.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcre_exec.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -50,8 +50,7 @@
                        was set at compile time)
   PCRE_PARTIAL       Return PCRE_ERROR_PARTIAL for a partial match
 .sp
-There are restrictions on what may appear in a pattern when partial matching is
-requested. For details, see the
+For details of partial matching, see the
 .\" HREF
 \fBpcrepartial\fP
 .\"


Modified: code/trunk/doc/pcre_fullinfo.3
===================================================================
--- code/trunk/doc/pcre_fullinfo.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcre_fullinfo.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -37,6 +37,7 @@
   PCRE_INFO_NAMEENTRYSIZE   Size of name table entry
   PCRE_INFO_NAMETABLE       Pointer to name table
   PCRE_INFO_OKPARTIAL       Return 1 if partial matching can be tried
+                              (always returns 1 after release 8.00)
   PCRE_INFO_OPTIONS         Option bits used for compilation
   PCRE_INFO_SIZE            Size of compiled pattern
   PCRE_INFO_STUDYSIZE       Size of study data


Modified: code/trunk/doc/pcreapi.3
===================================================================
--- code/trunk/doc/pcreapi.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcreapi.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -1008,12 +1008,13 @@
   PCRE_INFO_OKPARTIAL
 .sp
 Return 1 if the pattern can be used for partial matching, otherwise 0. The
-fourth argument should point to an \fBint\fP variable. The
+fourth argument should point to an \fBint\fP variable. From release 8.00, this
+always returns 1, because the restrictions that previously applied to partial
+matching have been lifted. The
 .\" HREF
 \fBpcrepartial\fP
 .\"
-documentation lists the restrictions that apply to patterns when partial
-matching is used.
+documentation gives details of partial matching.
 .sp
   PCRE_INFO_OPTIONS
 .sp
@@ -1374,8 +1375,8 @@
 the subject was reached (that is, the subject partially matches the pattern and
 the failure to match occurred only because there were not enough subject
 characters), \fBpcre_exec()\fP returns PCRE_ERROR_PARTIAL instead of
-PCRE_ERROR_NOMATCH. When PCRE_PARTIAL is used, there are restrictions on what
-may appear in the pattern. These are discussed in the
+PCRE_ERROR_NOMATCH. The portion of the string that provided the longest partial
+match is set as the first matching string. There is further discussion in the
 .\" HREF
 \fBpcrepartial\fP
 .\"
@@ -1568,12 +1569,10 @@
 .sp
   PCRE_ERROR_BADPARTIAL     (-13)
 .sp
-The PCRE_PARTIAL option was used with a compiled pattern containing items that
-are not supported for partial matching. See the
-.\" HREF
-\fBpcrepartial\fP
-.\"
-documentation for details of partial matching.
+This code is no longer in use. It was formerly returned when the PCRE_PARTIAL
+option was used with a compiled pattern containing items that were not
+supported for partial matching. From release 8.00 onwards, there are no 
+restrictions on partial matching.
 .sp
   PCRE_ERROR_INTERNAL       (-14)
 .sp
@@ -1865,7 +1864,8 @@
 zero. The only bits that may be set are PCRE_ANCHORED, PCRE_NEWLINE_\fIxxx\fP,
 PCRE_NOTBOL, PCRE_NOTEOL, PCRE_NOTEMPTY, PCRE_NO_UTF8_CHECK, PCRE_PARTIAL,
 PCRE_DFA_SHORTEST, and PCRE_DFA_RESTART. All but the last three of these are
-the same as for \fBpcre_exec()\fP, so their description is not repeated here.
+exactly the same as for \fBpcre_exec()\fP, so their description is not repeated
+here.
 .sp
   PCRE_PARTIAL
 .sp
@@ -1874,8 +1874,8 @@
 \fBpcre_dfa_exec()\fP, the return code PCRE_ERROR_NOMATCH is converted into
 PCRE_ERROR_PARTIAL if the end of the subject is reached, there have been no
 complete matches, but there is still at least one matching possibility. The
-portion of the string that provided the partial match is set as the first
-matching string.
+portion of the string that provided the longest partial match is set as the
+first matching string.
 .sp
   PCRE_DFA_SHORTEST
 .sp
@@ -1996,6 +1996,6 @@
 .rs
 .sp
 .nf
-Last updated: 11 April 2009
+Last updated: 26 August 2009
 Copyright (c) 1997-2009 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcrecompat.3
===================================================================
--- code/trunk/doc/pcrecompat.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcrecompat.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -7,7 +7,7 @@
 This document describes the differences in the ways that PCRE and Perl handle
 regular expressions. The differences described here are mainly with respect to
 Perl 5.8, though PCRE versions 7.0 and later contain some features that are
-expected to be in the forthcoming Perl 5.10.
+in Perl 5.10.
 .P
 1. PCRE has only a subset of Perl's UTF-8 and Unicode support. Details of what
 it does have are given in the
@@ -143,6 +143,6 @@
 .rs
 .sp
 .nf
-Last updated: 11 September 2007
-Copyright (c) 1997-2007 University of Cambridge.
+Last updated: 25 August 2009
+Copyright (c) 1997-2009 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcrematching.3
===================================================================
--- code/trunk/doc/pcrematching.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcrematching.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -144,12 +144,7 @@
 match using the standard algorithm, you have to do kludgy things with
 callouts.
 .P
-2. There is much better support for partial matching. The restrictions on the
-content of the pattern that apply when using the standard algorithm for partial
-matching do not apply to the alternative algorithm. For non-anchored patterns,
-the starting position of a partial match is available.
-.P
-3. Because the alternative algorithm scans the subject string just once, and
+2. Because the alternative algorithm scans the subject string just once, and
 never needs to backtrack, it is possible to pass very long subject strings to
 the matching function in several pieces, checking for partial matching each
 time.
@@ -183,6 +178,6 @@
 .rs
 .sp
 .nf
-Last updated: 19 April 2008
-Copyright (c) 1997-2008 University of Cambridge.
+Last updated: 25 August 2009
+Copyright (c) 1997-2009 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcrepartial.3
===================================================================
--- code/trunk/doc/pcrepartial.3    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcrepartial.3    2009-08-26 15:38:32 UTC (rev 426)
@@ -25,18 +25,32 @@
 .P
 PCRE supports the concept of partial matching by means of the PCRE_PARTIAL
 option, which can be set when calling \fBpcre_exec()\fP or
-\fBpcre_dfa_exec()\fP. When this flag is set for \fBpcre_exec()\fP, the return
-code PCRE_ERROR_NOMATCH is converted into PCRE_ERROR_PARTIAL if at any time
-during the matching process the last part of the subject string matched part of
-the pattern. Unfortunately, for non-anchored matching, it is not possible to
-obtain the position of the start of the partial match. No captured data is set
-when PCRE_ERROR_PARTIAL is returned.
+\fBpcre_dfa_exec()\fP. 
 .P
+When PCRE_PARTIAL is set for \fBpcre_exec()\fP, the return code
+PCRE_ERROR_NOMATCH is converted into PCRE_ERROR_PARTIAL if at any time during
+the matching process the last part of the subject string matched part of the
+pattern. If there are at least two slots in the offsets vector, they are filled
+in with the offsets of the longest found string that partially matched. No
+other captured data is set when PCRE_ERROR_PARTIAL is returned. The second
+offset is always that for the end of the subject. Consider this pattern:
+.sp
+  /123\ew+X|dogY/
+.sp
+If this is matched against the subject string "abc123dog", both
+alternatives fail to match, but the end of the subject is reached, so
+PCRE_ERROR_PARTIAL is returned instead of PCRE_ERROR_NOMATCH if the
+PCRE_PARTIAL option is set. The offsets are set to 3 and 9, identifying
+"123dog" as the longest partial match that was found. (In this example, there 
+are two partial matches, because "dog" on its own partially matches the second
+alternative.)
+.P
 When PCRE_PARTIAL is set for \fBpcre_dfa_exec()\fP, the return code
 PCRE_ERROR_NOMATCH is converted into PCRE_ERROR_PARTIAL if the end of the
 subject is reached, there have been no complete matches, but there is still at
 least one matching possibility. The portion of the string that provided the
-partial match is set as the first matching string.
+longest partial match is set as the first matching string, provided there are 
+at least two slots in the offsets vector.
 .P
 Using PCRE_PARTIAL disables one of PCRE's optimizations. PCRE remembers the
 last literal byte in a pattern, and abandons matching immediately if such a
@@ -44,35 +58,21 @@
 for a subject string that might match only partially.
 .
 .
-.SH "RESTRICTED PATTERNS FOR PCRE_PARTIAL"
+.SH "FORMERLY RESTRICTED PATTERNS FOR PCRE_PARTIAL"
 .rs
 .sp
-Because of the way certain internal optimizations are implemented in the
-\fBpcre_exec()\fP function, the PCRE_PARTIAL option cannot be used with all
-patterns. These restrictions do not apply when \fBpcre_dfa_exec()\fP is used.
-For \fBpcre_exec()\fP, repeated single characters such as
-.sp
-  a{2,4}
-.sp
-and repeated single metasequences such as
-.sp
-  \ed+
-.sp
-are not permitted if the maximum number of occurrences is greater than one.
-Optional items such as \ed? (where the maximum is one) are permitted.
-Quantifiers with any values are permitted after parentheses, so the invalid
-examples above can be coded thus:
-.sp
-  (a){2,4}
-  (\ed)+
-.sp
-These constructions run more slowly, but for the kinds of application that are
-envisaged for this facility, this is not felt to be a major restriction.
+For releases of PCRE prior to 8.00, because of the way certain internal
+optimizations were implemented in the \fBpcre_exec()\fP function, the
+PCRE_PARTIAL option could not be used with all patterns. From release 8.00
+onwards, the restrictions no longer apply, and partial matching can be
+requested for any pattern.
 .P
-If PCRE_PARTIAL is set for a pattern that does not conform to the restrictions,
-\fBpcre_exec()\fP returns the error code PCRE_ERROR_BADPARTIAL (-13).
-You can use the PCRE_INFO_OKPARTIAL call to \fBpcre_fullinfo()\fP to find out
-if a compiled pattern can be used for partial matching.
+Items that were formerly restricted were repeated single characters and
+repeated metasequences. If PCRE_PARTIAL was set for a pattern that did not
+conform to the restrictions, \fBpcre_exec()\fP returned the error code
+PCRE_ERROR_BADPARTIAL (-13). This error code is no longer in use. The
+PCRE_INFO_OKPARTIAL call to \fBpcre_fullinfo()\fP to find out if a compiled
+pattern can be used for partial matching now always returns 1.
 .
 .
 .SH "EXAMPLE OF PARTIAL MATCHING USING PCRETEST"
@@ -87,9 +87,9 @@
    0: 25jun04
    1: jun
   data> 25dec3\eP
-  Partial match
+  Partial match: 23dec3
   data> 3ju\eP
-  Partial match
+  Partial match: 3ju
   data> 3juj\eP
   No match
   data> j\eP
@@ -97,24 +97,29 @@
 .sp
 The first data string is matched completely, so \fBpcretest\fP shows the
 matched substrings. The remaining four strings do not match the complete
-pattern, but the first two are partial matches. The same test, using
-\fBpcre_dfa_exec()\fP matching (by means of the \eD escape sequence), produces
-the following output:
+pattern, but the first two are partial matches. Similar output is obtained
+when \fBpcre_dfa_exec()\fP is used.
+.
+.                                                          
+.SH "ISSUES WITH PARTIAL MATCHING"
+.rs
 .sp
-    re> /^\ed?\ed(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\ed\ed$/
-  data> 25jun04\eP\eD
-   0: 25jun04
-  data> 23dec3\eP\eD
-  Partial match: 23dec3
-  data> 3ju\eP\eD
-  Partial match: 3ju
-  data> 3juj\eP\eD
-  No match
-  data> j\eP\eD
-  No match
+Certain types of pattern may behave in unintuitive ways when partial matching
+is requested, whichever matching function is used. For example, matching a
+pattern that ends with (*FAIL), or any other assertion that causes a match to
+fail without inspecting any data, yields PCRE_ERROR_PARTIAL rather than
+PCRE_ERROR_NOMATCH:
 .sp
-Notice that in this case the portion of the string that was matched is made
-available.
+    re> /a+(*FAIL)/
+  data> aaa\eP
+  Partial match: aaa
+.sp
+Although (*FAIL) itself could possibly be made a special case, there are other
+assertions, for example (?!), which behave in the same way, and it is not
+possible to catch all cases. For consistency, therefore, there are no 
+exceptions to the rule that PCRE_ERROR_PARTIAL is returned instead of 
+PCRE_ERROR_NOMATCH if at any time during the match the end of the subject
+string was reached.
 .
 .
 .SH "MULTI-SEGMENT MATCHING WITH pcre_dfa_exec()"
@@ -126,7 +131,8 @@
 time setting the PCRE_DFA_RESTART option. You must also pass the same working
 space as before, because this is where details of the previous partial match
 are stored. Here is an example using \fBpcretest\fP, using the \eR escape
-sequence to set the PCRE_DFA_RESTART option (\eP and \eD are as above):
+sequence to set the PCRE_DFA_RESTART option (\eP sets the PCRE_PARTIAL option, 
+and \eD specifies the use of \fBpcre_dfa_exec()\fP):
 .sp
     re> /^\ed?\ed(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\ed\ed$/
   data> 23ja\eP\eD
@@ -142,8 +148,35 @@
 .P
 You can set PCRE_PARTIAL with PCRE_DFA_RESTART to continue partial matching
 over multiple segments. This facility can be used to pass very long subject
-strings to \fBpcre_dfa_exec()\fP. However, some care is needed for certain
-types of pattern.
+strings to \fBpcre_dfa_exec()\fP.
+.
+.
+.SH "MULTI-SEGMENT MATCHING WITH pcre_exec()"
+.rs
+.sp
+From release 8.00, \fBpcre_exec()\fP can also be used to do multi-segment 
+matching. Unlike \fBpcre_dfa_exec()\fP, it is not possible to restart the 
+previous match with a new segment of data. Instead, new data must be added to 
+the previous subject string, and the entire match re-run, starting from the 
+point where the partial match occurred. Earlier data can be discarded.
+Consider an unanchored pattern that matches dates:
+.sp
+    re> /\ed?\ed(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\ed\ed/
+  data> The date is 23ja\eP
+  Partial match: 23ja
+.sp
+The this stage, an application could discard the text preceding "23ja", add on 
+text from the next segment, and call \fBpcre_exec()\fP again. Unlike 
+\fBpcre_dfa_exec()\fP, the entire matching string must always be available, and 
+the complete matching process occurs for each call, so more memory and more 
+processing time is needed.
+.
+.                                                          
+.SH "ISSUES WITH MULTI-SEGMENT MATCHING"
+.rs
+.sp
+Certain types of pattern may give problems with multi-segment matching, 
+whichever matching function is used.
 .P
 1. If the pattern contains tests for the beginning or end of a line, you need
 to pass the PCRE_NOTBOL or PCRE_NOTEOL options, as appropriate, when the
@@ -151,19 +184,20 @@
 .P
 2. If the pattern contains backward assertions (including \eb or \eB), you need
 to arrange for some overlap in the subject strings to allow for this. For
-example, you could pass the subject in chunks that are 500 bytes long, but in
-a buffer of 700 bytes, with the starting offset set to 200 and the previous 200
-bytes at the start of the buffer.
+example, using \fBpcre_dfa_exec()\fP, you could pass the subject in chunks that
+are 500 bytes long, but in a buffer of 700 bytes, with the starting offset set
+to 200 and the previous 200 bytes at the start of the buffer.
 .P
 3. Matching a subject string that is split into multiple segments does not
 always produce exactly the same result as matching over one single long string.
 The difference arises when there are multiple matching possibilities, because a
-partial match result is given only when there are no completed matches in a
-call to \fBpcre_dfa_exec()\fP. This means that as soon as the shortest match has
-been found, continuation to a new subject segment is no longer possible.
-Consider this \fBpcretest\fP example:
+partial match result is given only when there are no completed matches. This
+means that as soon as the shortest match has been found, continuation to a new
+subject segment is no longer possible. Consider this \fBpcretest\fP example:
 .sp
     re> /dog(sbody)?/
+  data> dogsb\eP
+   0: dog    
   data> do\eP\eD
   Partial match: do
   data> gsb\eR\eP\eD
@@ -172,24 +206,28 @@
    0: dogsbody
    1: dog
 .sp
-The pattern matches the words "dog" or "dogsbody". When the subject is
-presented in several parts ("do" and "gsb" being the first two) the match stops
-when "dog" has been found, and it is not possible to continue. On the other
-hand, if "dogsbody" is presented as a single string, both matches are found.
+The pattern matches "dog" or "dogsbody". The first data line passes the string
+"dogsb" to \fBpcre_exec()\fP, setting the PCRE_PARTIAL option. Although the
+string is a partial match for "dogsbody", the result is not PCRE_ERROR_PARTIAL,
+because the shorter string "dog" is a complete match. Similarly, when the
+subject is presented to \fBpcre_dfa_exec()\fP in several parts ("do" and "gsb"
+being the first two) the match stops when "dog" has been found, and it is not
+possible to continue. On the other hand, if "dogsbody" is presented as a single
+string, \fBpcre_dfa_exec()\fP finds both matches.
 .P
 Because of this phenomenon, it does not usually make sense to end a pattern
 that is going to be matched in this way with a variable repeat.
 .P
 4. Patterns that contain alternatives at the top level which do not all
-start with the same pattern item may not work as expected. For example,
-consider this pattern:
+start with the same pattern item may not work as expected when 
+\fBpcre_dfa_exec()\fP is used. For example, consider this pattern:
 .sp
   1234|3789
 .sp
 If the first part of the subject is "ABC123", a partial match of the first
 alternative is found at offset 3. There is no partial match for the second
 alternative, because such a match does not start at the same point in the
-subject string. Attempting to continue with the string "789" does not yield a
+subject string. Attempting to continue with the string "7890" does not yield a
 match because only those alternatives that match at one point in the subject
 are remembered. The problem arises because the start of the second alternative
 matches within the first alternative. There is no problem with anchored
@@ -197,7 +235,16 @@
 .sp
   1234|ABCD
 .sp
-where no string can be a partial match for both alternatives.
+where no string can be a partial match for both alternatives. This is not a
+problem if \fPpcre_exec()\fP is used, because the entire match has to be rerun 
+each time:
+.sp
+    re> /1234|3789/
+  data> ABC123\eP
+  Partial match: 123
+  data> 1237890
+   0: 3789
+.sp        
 .
 .
 .SH AUTHOR
@@ -214,6 +261,6 @@
 .rs
 .sp
 .nf
-Last updated: 04 June 2007
-Copyright (c) 1997-2007 University of Cambridge.
+Last updated: 26 August 2009
+Copyright (c) 1997-2009 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcretest.1
===================================================================
--- code/trunk/doc/pcretest.1    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/doc/pcretest.1    2009-08-26 15:38:32 UTC (rev 426)
@@ -460,10 +460,10 @@
 .P
 When a match succeeds, pcretest outputs the list of captured substrings that
 \fBpcre_exec()\fP returns, starting with number 0 for the string that matched
-the whole pattern. Otherwise, it outputs "No match" or "Partial match"
-when \fBpcre_exec()\fP returns PCRE_ERROR_NOMATCH or PCRE_ERROR_PARTIAL,
-respectively, and otherwise the PCRE negative error number. Here is an example
-of an interactive \fBpcretest\fP run.
+the whole pattern. Otherwise, it outputs "No match" or "Partial match" followed 
+by the partially matching substring when \fBpcre_exec()\fP returns
+PCRE_ERROR_NOMATCH or PCRE_ERROR_PARTIAL, respectively, and otherwise the PCRE
+negative error number. Here is an example of an interactive \fBpcretest\fP run.
 .sp
   $ pcretest
   PCRE version 7.0 30-Nov-2006
@@ -723,6 +723,6 @@
 .rs
 .sp
 .nf
-Last updated: 10 March 2009
+Last updated: 25 August 2009
 Copyright (c) 1997-2009 University of Cambridge.
 .fi


Modified: code/trunk/pcre_compile.c
===================================================================
--- code/trunk/pcre_compile.c    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcre_compile.c    2009-08-26 15:38:32 UTC (rev 426)
@@ -1423,10 +1423,8 @@
     branchlength++;
     cc += 2;
 #ifdef SUPPORT_UTF8
-    if ((options & PCRE_UTF8) != 0)
-      {
-      while ((*cc & 0xc0) == 0x80) cc++;
-      }
+    if ((options & PCRE_UTF8) != 0 && cc[-1] >= 0xc0) 
+      cc += _pcre_utf8_table4[cc[-1] & 0x3f];
 #endif
     break;


@@ -1437,10 +1435,8 @@
     branchlength += GET2(cc,1);
     cc += 4;
 #ifdef SUPPORT_UTF8
-    if ((options & PCRE_UTF8) != 0)
-      {
-      while((*cc & 0x80) == 0x80) cc++;
-      }
+    if ((options & PCRE_UTF8) != 0 && cc[-1] >= 0xc0) 
+      cc += _pcre_utf8_table4[cc[-1] & 0x3f];
 #endif
     break;


@@ -1912,10 +1908,13 @@
     case OP_QUERY:
     case OP_MINQUERY:
     case OP_POSQUERY:
+    if (utf8 && code[1] >= 0xc0) code += _pcre_utf8_table4[code[1] & 0x3f];
+    break;
+ 
     case OP_UPTO:
     case OP_MINUPTO:
     case OP_POSUPTO:
-    if (utf8) while ((code[2] & 0xc0) == 0x80) code++;
+    if (utf8 && code[3] >= 0xc0) code += _pcre_utf8_table4[code[3] & 0x3f];
     break;
 #endif
     }
@@ -3869,11 +3868,16 @@


       if (repeat_max == 0) goto END_REPEAT;


+      /*--------------------------------------------------------------------*/ 
+      /* This code is obsolete from release 8.00; the restriction was finally
+      removed: */
+       
       /* All real repeats make it impossible to handle partial matching (maybe
       one day we will be able to remove this restriction). */
+       
+      /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */
+      /*--------------------------------------------------------------------*/ 


-      if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL;
-
       /* Combine the op_type with the repeat_type */


       repeat_type += op_type;
@@ -4019,10 +4023,15 @@
         goto END_REPEAT;
         }


+      /*--------------------------------------------------------------------*/ 
+      /* This code is obsolete from release 8.00; the restriction was finally
+      removed: */
+
       /* All real repeats make it impossible to handle partial matching (maybe
       one day we will be able to remove this restriction). */


-      if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL;
+      /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */
+      /*--------------------------------------------------------------------*/ 


       if (repeat_min == 0 && repeat_max == -1)
         *code++ = OP_CRSTAR + repeat_type;
@@ -4337,11 +4346,20 @@
     if (possessive_quantifier)
       {
       int len;
-      if (*tempcode == OP_EXACT || *tempcode == OP_TYPEEXACT ||
-          *tempcode == OP_NOTEXACT)
+       
+      if (*tempcode == OP_TYPEEXACT)
         tempcode += _pcre_OP_lengths[*tempcode] +
-          ((*tempcode == OP_TYPEEXACT &&
-             (tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP))? 2:0);
+          ((tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP)? 2 : 0);   
+           
+      else if (*tempcode == OP_EXACT || *tempcode == OP_NOTEXACT)
+        {
+        tempcode += _pcre_OP_lengths[*tempcode];
+#ifdef SUPPORT_UTF8
+        if (utf8 && tempcode[-1] >= 0xc0)
+          tempcode += _pcre_utf8_table4[tempcode[-1] & 0x3f];
+#endif
+        }         
+ 
       len = code - tempcode;
       if (len > 0) switch (*tempcode)
         {


Modified: code/trunk/pcre_dfa_exec.c
===================================================================
--- code/trunk/pcre_dfa_exec.c    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcre_dfa_exec.c    2009-08-26 15:38:32 UTC (rev 426)
@@ -2157,8 +2157,8 @@


 /* ========================================================================== */
       /* These are the opcodes for fancy brackets of various kinds. We have
-      to use recursion in order to handle them. The "always failing" assersion
-      (?!) is optimised when compiling to OP_FAIL, so we have to support that,
+      to use recursion in order to handle them. The "always failing" assertion
+      (?!) is optimised to OP_FAIL when compiling, so we have to support that,
       though the other "backtracking verbs" are not supported. */


       case OP_FAIL:


Modified: code/trunk/pcre_exec.c
===================================================================
--- code/trunk/pcre_exec.c    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcre_exec.c    2009-08-26 15:38:32 UTC (rev 426)
@@ -398,10 +398,23 @@


/* This function is called recursively in many circumstances. Whenever it
returns a negative (error) response, the outer incarnation must also return the
-same response.
+same response. */

-Performance note: It might be tempting to extract commonly used fields from the
-md structure (e.g. utf8, end_subject) into individual variables to improve
+/* These macros pack up tests that are used for partial matching, and which
+appears several times in the code. We set the "hit end" flag if the pointer is
+at the end of the subject and also past the start of the subject (i.e.
+something has been matched). The second one is used when we already know we are
+past the end of the subject. */
+
+#define CHECK_PARTIAL()\
+  if (md->partial && eptr >= md->end_subject && eptr > mstart)\
+    md->hitend = TRUE
+
+#define SCHECK_PARTIAL()\
+  if (md->partial && eptr > mstart) md->hitend = TRUE
+
+/* Performance note: It might be tempting to extract commonly used fields from
+the md structure (e.g. utf8, end_subject) into individual variables to improve
 performance. Tests using gcc on a SPARC disproved this; in the first case, it
 made performance worse.


@@ -643,12 +656,10 @@
op = *ecode;

/* For partial matching, remember if we ever hit the end of the subject after
- matching at least one subject character. */
+ matching at least one subject character. This code is now wrapped in a macro
+ because it appears several times below. */

-  if (md->partial &&
-      eptr >= md->end_subject &&
-      eptr > mstart)
-    md->hitend = TRUE;
+  CHECK_PARTIAL();


   switch(op)
     {
@@ -1857,7 +1868,11 @@


       for (i = 1; i <= min; i++)
         {
-        if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH);
+        if (!match_ref(offset, eptr, length, md, ims)) 
+          {
+          CHECK_PARTIAL(); 
+          RRETURN(MATCH_NOMATCH);
+          } 
         eptr += length;
         }


@@ -1875,7 +1890,10 @@
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM14);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max || !match_ref(offset, eptr, length, md, ims))
+            {
+            CHECK_PARTIAL();  
             RRETURN(MATCH_NOMATCH);
+            } 
           eptr += length;
           }
         /* Control never gets here */
@@ -1891,6 +1909,7 @@
           if (!match_ref(offset, eptr, length, md, ims)) break;
           eptr += length;
           }
+        CHECK_PARTIAL();   
         while (eptr >= pp)
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM15);
@@ -1958,7 +1977,11 @@
         {
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            CHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           if (c > 255)
             {
@@ -1976,7 +1999,11 @@
         {
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            CHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            } 
           c = *eptr++;
           if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
           }
@@ -2000,7 +2027,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM16);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             if (c > 255)
               {
@@ -2020,7 +2056,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM17);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             c = *eptr++;
             if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
             }
@@ -2053,6 +2098,7 @@
               }
             eptr += len;
             }
+          CHECK_PARTIAL();   
           for (;;)
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM18);
@@ -2072,6 +2118,7 @@
             if ((data[c/8] & (1 << (c&7))) == 0) break;
             eptr++;
             }
+          CHECK_PARTIAL();   
           while (eptr >= pp)
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM19);
@@ -2129,7 +2176,11 @@


       for (i = 1; i <= min; i++)
         {
-        if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+        if (eptr >= md->end_subject) 
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          } 
         GETCHARINCTEST(c, eptr);
         if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH);
         }
@@ -2148,7 +2199,16 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM20);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (fi >= max) 
+            {
+            CHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINCTEST(c, eptr);
           if (!_pcre_xclass(c, data)) RRETURN(MATCH_NOMATCH);
           }
@@ -2168,6 +2228,7 @@
           if (!_pcre_xclass(c, data)) break;
           eptr += len;
           }
+        CHECK_PARTIAL();   
         for(;;)
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM21);
@@ -2308,9 +2369,7 @@
     max = rep_max[c];                 /* zero for max => infinity */
     if (max == 0) max = INT_MAX;


-    /* Common code for all repeated single-character matches. We can give
-    up quickly if there are fewer than the minimum number of characters left in
-    the subject. */
+    /* Common code for all repeated single-character matches. */


     REPEATCHAR:
 #ifdef SUPPORT_UTF8
@@ -2319,7 +2378,6 @@
       length = 1;
       charptr = ecode;
       GETCHARLEN(fc, ecode, length);
-      if (min * length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
       ecode += length;


       /* Handle multibyte character matching specially here. There is
@@ -2337,18 +2395,18 @@


         for (i = 1; i <= min; i++)
           {
-          if (memcmp(eptr, charptr, length) == 0) eptr += length;
+          if (eptr <= md->end_subject - length &&
+            memcmp(eptr, charptr, length) == 0) eptr += length;
 #ifdef SUPPORT_UCP
-          /* Need braces because of following else */
-          else if (oclength == 0) { RRETURN(MATCH_NOMATCH); }
+          else if (oclength > 0 &&
+                   eptr <= md->end_subject - oclength &&
+                   memcmp(eptr, occhars, oclength) == 0) eptr += oclength;
+#endif  /* SUPPORT_UCP */
           else
             {
-            if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH);
-            eptr += oclength;
+            CHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
             }
-#else   /* without SUPPORT_UCP */
-          else { RRETURN(MATCH_NOMATCH); }
-#endif  /* SUPPORT_UCP */
           }


         if (min == max) continue;
@@ -2359,19 +2417,23 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM22);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
-            if (memcmp(eptr, charptr, length) == 0) eptr += length;
+            if (fi >= max)
+              {
+              CHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            if (eptr <= md->end_subject - length &&
+              memcmp(eptr, charptr, length) == 0) eptr += length;
 #ifdef SUPPORT_UCP
-            /* Need braces because of following else */
-            else if (oclength == 0) { RRETURN(MATCH_NOMATCH); }
+            else if (oclength > 0 &&
+                     eptr <= md->end_subject - oclength &&
+                     memcmp(eptr, occhars, oclength) == 0) eptr += oclength;
+#endif  /* SUPPORT_UCP */
             else
               {
-              if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH);
-              eptr += oclength;
+              CHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
               }
-#else   /* without SUPPORT_UCP */
-            else { RRETURN (MATCH_NOMATCH); }
-#endif  /* SUPPORT_UCP */
             }
           /* Control never gets here */
           }
@@ -2381,33 +2443,31 @@
           pp = eptr;
           for (i = min; i < max; i++)
             {
-            if (eptr > md->end_subject - length) break;
-            if (memcmp(eptr, charptr, length) == 0) eptr += length;
+            if (eptr <= md->end_subject - length &&
+                memcmp(eptr, charptr, length) == 0) eptr += length;
 #ifdef SUPPORT_UCP
-            else if (oclength == 0) break;
-            else
-              {
-              if (memcmp(eptr, occhars, oclength) != 0) break;
-              eptr += oclength;
-              }
-#else   /* without SUPPORT_UCP */
+            else if (oclength > 0 &&
+                     eptr <= md->end_subject - oclength &&
+                     memcmp(eptr, occhars, oclength) == 0) eptr += oclength;
+#endif  /* SUPPORT_UCP */
             else break;
-#endif  /* SUPPORT_UCP */
             }


+          CHECK_PARTIAL();
           if (possessive) continue;
+           
           for(;;)
-           {
-           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM23);
-           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-           if (eptr == pp) RRETURN(MATCH_NOMATCH);
+            {
+            RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM23);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (eptr == pp) { RRETURN(MATCH_NOMATCH); }
 #ifdef SUPPORT_UCP
-           eptr--;
-           BACKCHAR(eptr);
+            eptr--;
+            BACKCHAR(eptr);
 #else   /* without SUPPORT_UCP */
-           eptr -= length;
+            eptr -= length;
 #endif  /* SUPPORT_UCP */
-           }
+            }
           }
         /* Control never gets here */
         }
@@ -2420,11 +2480,9 @@
 #endif  /* SUPPORT_UTF8 */


     /* When not in UTF-8 mode, load a single-byte character. */
-      {
-      if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
-      fc = *ecode++;
-      }


+    fc = *ecode++;
+
     /* The value of fc at this point is always less than 256, though we may or
     may not be in UTF-8 mode. The code is duplicated for the caseless and
     caseful cases, for speed, since matching characters is likely to be quite
@@ -2441,7 +2499,14 @@
       {
       fc = md->lcc[fc];
       for (i = 1; i <= min; i++)
+        {
+        if (eptr >= md->end_subject)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
         if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+        }
       if (min == max) continue;
       if (minimize)
         {
@@ -2449,9 +2514,17 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM24);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject ||
-              fc != md->lcc[*eptr++])
+          if (fi >= max)
+            {
+            CHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
+            }
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
           }
         /* Control never gets here */
         }
@@ -2463,7 +2536,10 @@
           if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break;
           eptr++;
           }
+           
+        CHECK_PARTIAL();   
         if (possessive) continue;
+         
         while (eptr >= pp)
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM25);
@@ -2479,7 +2555,15 @@


     else
       {
-      for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH);
+      for (i = 1; i <= min; i++) 
+        {
+        if (eptr >= md->end_subject)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        if (fc != *eptr++) RRETURN(MATCH_NOMATCH);
+        } 
       if (min == max) continue;
       if (minimize)
         {
@@ -2487,8 +2571,17 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM26);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject || fc != *eptr++)
+          if (fi >= max)
+            {
+            CHECK_PARTIAL();
             RRETURN(MATCH_NOMATCH);
+            }
+          if (eptr >= md->end_subject)
+            {        
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }  
+          if (fc != *eptr++) RRETURN(MATCH_NOMATCH);
           }
         /* Control never gets here */
         }
@@ -2500,6 +2593,7 @@
           if (eptr >= md->end_subject || fc != *eptr) break;
           eptr++;
           }
+        CHECK_PARTIAL();   
         if (possessive) continue;
         while (eptr >= pp)
           {
@@ -2593,12 +2687,9 @@
     max = rep_max[c];                 /* zero for max => infinity */
     if (max == 0) max = INT_MAX;


-    /* Common code for all repeated single-byte matches. We can give up quickly
-    if there are fewer than the minimum number of bytes left in the
-    subject. */
+    /* Common code for all repeated single-byte matches. */


     REPEATNOTCHAR:
-    if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
     fc = *ecode++;


     /* The code is duplicated for the caseless and caseful cases, for speed,
@@ -2623,6 +2714,11 @@
         register unsigned int d;
         for (i = 1; i <= min; i++)
           {
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);  
+            }    
           GETCHARINC(d, eptr);
           if (d < 256) d = md->lcc[d];
           if (fc == d) RRETURN(MATCH_NOMATCH);
@@ -2634,7 +2730,14 @@
       /* Not UTF-8 mode */
         {
         for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);  
+            }    
           if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+          } 
         }


       if (min == max) continue;
@@ -2650,11 +2753,19 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM28);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max)
+              {
+              CHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }     
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(d, eptr);
             if (d < 256) d = md->lcc[d];
             if (fc == d) RRETURN(MATCH_NOMATCH);
-
             }
           }
         else
@@ -2665,8 +2776,17 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM29);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++])
+            if (fi >= max)
+              {
+              CHECK_PARTIAL();
               RRETURN(MATCH_NOMATCH);
+              }
+            if (eptr >= md->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
             }
           }
         /* Control never gets here */
@@ -2692,6 +2812,7 @@
             if (fc == d) break;
             eptr += len;
             }
+        CHECK_PARTIAL();     
         if (possessive) continue;
         for(;;)
             {
@@ -2710,6 +2831,7 @@
             if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break;
             eptr++;
             }
+          CHECK_PARTIAL();   
           if (possessive) continue;
           while (eptr >= pp)
             {
@@ -2735,6 +2857,11 @@
         register unsigned int d;
         for (i = 1; i <= min; i++)
           {
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);  
+            }    
           GETCHARINC(d, eptr);
           if (fc == d) RRETURN(MATCH_NOMATCH);
           }
@@ -2744,7 +2871,14 @@
       /* Not UTF-8 mode */
         {
         for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);  
+            }    
           if (fc == *eptr++) RRETURN(MATCH_NOMATCH);
+          } 
         }


       if (min == max) continue;
@@ -2760,7 +2894,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM32);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(d, eptr);
             if (fc == d) RRETURN(MATCH_NOMATCH);
             }
@@ -2773,8 +2916,17 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM33);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject || fc == *eptr++)
+            if (fi >= max)
+              {
+              CHECK_PARTIAL();
               RRETURN(MATCH_NOMATCH);
+              }
+            if (eptr >= md->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }   
+            if (fc == *eptr++) RRETURN(MATCH_NOMATCH);
             }
           }
         /* Control never gets here */
@@ -2799,6 +2951,7 @@
             if (fc == d) break;
             eptr += len;
             }
+          CHECK_PARTIAL();   
           if (possessive) continue;
           for(;;)
             {
@@ -2817,6 +2970,7 @@
             if (eptr >= md->end_subject || fc == *eptr) break;
             eptr++;
             }
+          CHECK_PARTIAL();   
           if (possessive) continue;
           while (eptr >= pp)
             {
@@ -2908,13 +3062,10 @@


     /* First, ensure the minimum number of matches are present. Use inline
     code for maximizing the speed, and do the type test once at the start
-    (i.e. keep it out of the loop). Also we can test that there are at least
-    the minimum number of bytes before we start. This isn't as effective in
-    UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that
+    (i.e. keep it out of the loop). Separate the UTF-8 code completely as that
     is tidier. Also separate the UCP code, which can be the same for both UTF-8
     and single-bytes. */


-    if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
     if (min > 0)
       {
 #ifdef SUPPORT_UCP
@@ -2926,7 +3077,11 @@
           if (prop_fail_result) RRETURN(MATCH_NOMATCH);
           for (i = 1; i <= min; i++)
             {
-            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINCTEST(c, eptr);
             }
           break;
@@ -2934,7 +3089,11 @@
           case PT_LAMP:
           for (i = 1; i <= min; i++)
             {
-            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINCTEST(c, eptr);
             prop_chartype = UCD_CHARTYPE(c);
             if ((prop_chartype == ucp_Lu ||
@@ -2947,7 +3106,11 @@
           case PT_GC:
           for (i = 1; i <= min; i++)
             {
-            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINCTEST(c, eptr);
             prop_category = UCD_CATEGORY(c);
             if ((prop_category == prop_value) == prop_fail_result)
@@ -2958,7 +3121,11 @@
           case PT_PC:
           for (i = 1; i <= min; i++)
             {
-            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINCTEST(c, eptr);
             prop_chartype = UCD_CHARTYPE(c);
             if ((prop_chartype == prop_value) == prop_fail_result)
@@ -2969,7 +3136,11 @@
           case PT_SC:
           for (i = 1; i <= min; i++)
             {
-            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINCTEST(c, eptr);
             prop_script = UCD_SCRIPT(c);
             if ((prop_script == prop_value) == prop_fail_result)
@@ -2989,16 +3160,19 @@
         {
         for (i = 1; i <= min; i++)
           {
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINCTEST(c, eptr);
           prop_category = UCD_CATEGORY(c);
           if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
           while (eptr < md->end_subject)
             {
             int len = 1;
-            if (!utf8) c = *eptr; else
-              {
-              GETCHARLEN(c, eptr, len);
-              }
+            if (!utf8) c = *eptr;
+              else { GETCHARLEN(c, eptr, len); }
             prop_category = UCD_CATEGORY(c);
             if (prop_category != ucp_M) break;
             eptr += len;
@@ -3017,8 +3191,12 @@
         case OP_ANY:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject || IS_NEWLINE(eptr))
+          if (eptr >= md->end_subject)
+            {
+            SCHECK_PARTIAL();  
             RRETURN(MATCH_NOMATCH);
+            } 
+          if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
           eptr++;
           while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
           }
@@ -3027,20 +3205,29 @@
         case OP_ALLANY:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            } 
           eptr++;
           while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
           }
         break;


         case OP_ANYBYTE:
+        if (eptr > md->end_subject - min) RRETURN(MATCH_NOMATCH); 
         eptr += min;
         break;


         case OP_ANYNL:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           switch(c)
             {
@@ -3066,7 +3253,11 @@
         case OP_NOT_HSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           switch(c)
             {
@@ -3098,7 +3289,11 @@
         case OP_HSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           switch(c)
             {
@@ -3130,7 +3325,11 @@
         case OP_NOT_VSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           switch(c)
             {
@@ -3150,7 +3349,11 @@
         case OP_VSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           switch(c)
             {
@@ -3170,7 +3373,11 @@
         case OP_NOT_DIGIT:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINC(c, eptr);
           if (c < 128 && (md->ctypes[c] & ctype_digit) != 0)
             RRETURN(MATCH_NOMATCH);
@@ -3180,9 +3387,13 @@
         case OP_DIGIT:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject ||
-             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0)
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
+            } 
+          if (*eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0)
+            RRETURN(MATCH_NOMATCH);
           /* No need to skip more bytes - we know it's a 1-byte character */
           }
         break;
@@ -3190,9 +3401,13 @@
         case OP_NOT_WHITESPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject ||
-             (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0))
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
+            } 
+          if (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0)
+            RRETURN(MATCH_NOMATCH);
           while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80);
           }
         break;
@@ -3200,9 +3415,13 @@
         case OP_WHITESPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject ||
-             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0)
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
+            } 
+          if (*eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0)
+            RRETURN(MATCH_NOMATCH);
           /* No need to skip more bytes - we know it's a 1-byte character */
           }
         break;
@@ -3220,9 +3439,13 @@
         case OP_WORDCHAR:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject ||
-             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0)
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
+            } 
+          if (*eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0)
+            RRETURN(MATCH_NOMATCH);
           /* No need to skip more bytes - we know it's a 1-byte character */
           }
         break;
@@ -3235,34 +3458,41 @@
 #endif     /* SUPPORT_UTF8 */


       /* Code for the non-UTF-8 case for minimum matching of operators other
-      than OP_PROP and OP_NOTPROP. We can assume that there are the minimum
-      number of bytes present, as this was tested above. */
+      than OP_PROP and OP_NOTPROP. */


       switch(ctype)
         {
         case OP_ANY:
         for (i = 1; i <= min; i++)
           {
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
           eptr++;
           }
         break;


         case OP_ALLANY:
+        if (eptr > md->end_subject - min) RRETURN(MATCH_NOMATCH); 
         eptr += min;
         break;


         case OP_ANYBYTE:
+        if (eptr > md->end_subject - min) RRETURN(MATCH_NOMATCH); 
         eptr += min;
         break;


-        /* Because of the CRLF case, we can't assume the minimum number of
-        bytes are present in this case. */
-
         case OP_ANYNL:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           switch(*eptr++)
             {
             default: RRETURN(MATCH_NOMATCH);
@@ -3284,7 +3514,11 @@
         case OP_NOT_HSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           switch(*eptr++)
             {
             default: break;
@@ -3299,7 +3533,11 @@
         case OP_HSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           switch(*eptr++)
             {
             default: RRETURN(MATCH_NOMATCH);
@@ -3314,7 +3552,11 @@
         case OP_NOT_VSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           switch(*eptr++)
             {
             default: break;
@@ -3331,7 +3573,11 @@
         case OP_VSPACE:
         for (i = 1; i <= min; i++)
           {
-          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           switch(*eptr++)
             {
             default: RRETURN(MATCH_NOMATCH);
@@ -3347,34 +3593,76 @@


         case OP_NOT_DIGIT:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+          } 
         break;


         case OP_DIGIT:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+          } 
         break;


         case OP_NOT_WHITESPACE:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+          } 
         break;


         case OP_WHITESPACE:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+          } 
         break;


         case OP_NOT_WORDCHAR:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_word) != 0)
             RRETURN(MATCH_NOMATCH);
+          }   
         break;


         case OP_WORDCHAR:
         for (i = 1; i <= min; i++)
+          { 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           if ((md->ctypes[*eptr++] & ctype_word) == 0)
             RRETURN(MATCH_NOMATCH);
+          }   
         break;


         default:
@@ -3402,7 +3690,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM36);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             if (prop_fail_result) RRETURN(MATCH_NOMATCH);
             }
@@ -3413,7 +3710,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM37);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             prop_chartype = UCD_CHARTYPE(c);
             if ((prop_chartype == ucp_Lu ||
@@ -3428,7 +3734,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM38);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             prop_category = UCD_CATEGORY(c);
             if ((prop_category == prop_value) == prop_fail_result)
@@ -3441,7 +3756,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM39);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             prop_chartype = UCD_CHARTYPE(c);
             if ((prop_chartype == prop_value) == prop_fail_result)
@@ -3454,7 +3778,16 @@
             {
             RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM40);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (fi >= max) 
+              {
+              CHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
+            if (eptr >= md->end_subject) 
+              {
+              SCHECK_PARTIAL(); 
+              RRETURN(MATCH_NOMATCH);
+              } 
             GETCHARINC(c, eptr);
             prop_script = UCD_SCRIPT(c);
             if ((prop_script == prop_value) == prop_fail_result)
@@ -3476,17 +3809,24 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM41);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          if (fi >= max) 
+            {
+            CHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
           GETCHARINCTEST(c, eptr);
           prop_category = UCD_CATEGORY(c);
           if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
           while (eptr < md->end_subject)
             {
             int len = 1;
-            if (!utf8) c = *eptr; else
-              {
-              GETCHARLEN(c, eptr, len);
-              }
+            if (!utf8) c = *eptr;
+              else { GETCHARLEN(c, eptr, len); }
             prop_category = UCD_CATEGORY(c);
             if (prop_category != ucp_M) break;
             eptr += len;
@@ -3505,10 +3845,18 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM42);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject ||
-               (ctype == OP_ANY && IS_NEWLINE(eptr)))
+          if (fi >= max) 
+            {
+            CHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
-
+            } 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
+          if (ctype == OP_ANY && IS_NEWLINE(eptr))
+            RRETURN(MATCH_NOMATCH);
           GETCHARINC(c, eptr);
           switch(ctype)
             {
@@ -3664,10 +4012,18 @@
           {
           RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM43);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-          if (fi >= max || eptr >= md->end_subject ||
-               (ctype == OP_ANY && IS_NEWLINE(eptr)))
+          if (fi >= max) 
+            {
+            CHECK_PARTIAL(); 
             RRETURN(MATCH_NOMATCH);
-
+            } 
+          if (eptr >= md->end_subject) 
+            {
+            SCHECK_PARTIAL(); 
+            RRETURN(MATCH_NOMATCH);
+            } 
+          if (ctype == OP_ANY && IS_NEWLINE(eptr))
+            RRETURN(MATCH_NOMATCH);
           c = *eptr++;
           switch(ctype)
             {
@@ -3856,6 +4212,7 @@


         /* eptr is now past the end of the maximum run */


+        CHECK_PARTIAL();
         if (possessive) continue;
         for(;;)
           {
@@ -3892,6 +4249,7 @@


         /* eptr is now past the end of the maximum run */


+        CHECK_PARTIAL();
         if (possessive) continue;
         for(;;)
           {
@@ -4128,6 +4486,7 @@


         /* eptr is now past the end of the maximum run */


+        CHECK_PARTIAL();
         if (possessive) continue;
         for(;;)
           {
@@ -4283,6 +4642,7 @@


         /* eptr is now past the end of the maximum run */


+        CHECK_PARTIAL();
         if (possessive) continue;
         while (eptr >= pp)
           {
@@ -4450,6 +4810,7 @@
 const uschar *start_bits = NULL;
 USPTR start_match = (USPTR)subject + start_offset;
 USPTR end_subject;
+USPTR start_partial = NULL;
 USPTR req_byte_ptr = start_match - 1;


 pcre_study_data internal_study;
@@ -4607,8 +4968,9 @@
     }
   }


-/* Partial matching is supported only for a restricted set of regexes at the
-moment. */
+/* Partial matching was originally supported only for a restricted set of
+regexes; from release 8.00 there are no restrictions, but the bits are still
+defined (though never set). So there's no harm in leaving this code. */

 if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0)
   return PCRE_ERROR_BADPARTIAL;
@@ -4890,11 +5252,13 @@
       }
     }


- /* OK, we can now run the match. */
+ /* OK, we can now run the match. If "hitend" is set afterwards, remember the
+ first starting point for which a partial match was found. */

md->start_match_ptr = start_match;
md->match_call_count = 0;
rc = match(start_match, md->start_code, start_match, 2, md, ims, NULL, 0, 0);
+ if (md->hitend && start_partial == NULL) start_partial = start_match;

   switch(rc)
     {
@@ -5035,9 +5399,14 @@
   DPRINTF((">>>> error: returning %d\n", rc));
   return rc;
   }
-else if (md->partial && md->hitend)
+else if (md->partial && start_partial != NULL)
   {
   DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));
+  if (offsetcount > 1) 
+    {
+    offsets[0] = start_partial - (USPTR)subject;
+    offsets[1] = end_subject - (USPTR)subject;
+    }  
   return PCRE_ERROR_PARTIAL;
   }
 else


Modified: code/trunk/pcre_fullinfo.c
===================================================================
--- code/trunk/pcre_fullinfo.c    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcre_fullinfo.c    2009-08-26 15:38:32 UTC (rev 426)
@@ -144,6 +144,9 @@
   *((const uschar **)where) = (const uschar *)(_pcre_default_tables);
   break;


+  /* From release 8.00 this will always return TRUE because NOPARTIAL is
+  no longer ever set (the restrictions have been removed). */
+    
   case PCRE_INFO_OKPARTIAL:
   *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0;
   break;


Modified: code/trunk/pcre_internal.h
===================================================================
--- code/trunk/pcre_internal.h    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcre_internal.h    2009-08-26 15:38:32 UTC (rev 426)
@@ -535,7 +535,9 @@


/* Private flags containing information about the compiled regex. They used to
live at the top end of the options word, but that got almost full, so now they
-are in a 16-bit flags word. */
+are in a 16-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as
+the restrictions on partial matching have been lifted. It remains for backwards
+compatibility. */

 #define PCRE_NOPARTIAL     0x0001  /* can't use partial with this regex */
 #define PCRE_FIRSTSET      0x0002  /* first_byte is set */


Modified: code/trunk/pcretest.c
===================================================================
--- code/trunk/pcretest.c    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/pcretest.c    2009-08-26 15:38:32 UTC (rev 426)
@@ -2363,11 +2363,12 @@
       else if (count == PCRE_ERROR_PARTIAL)
         {
         fprintf(outfile, "Partial match");
-#if !defined NODFA
-        if ((all_use_dfa || use_dfa) && use_size_offsets > 2)
-          fprintf(outfile, ": %.*s", use_offsets[1] - use_offsets[0],
-            bptr + use_offsets[0]);
-#endif
+        if (use_size_offsets > 1)
+          {
+          fprintf(outfile, ": ");
+          pchars(bptr + use_offsets[0], use_offsets[1] - use_offsets[0],
+            outfile);   
+          }   
         fprintf(outfile, "\n");
         break;  /* Out of the /g loop */
         }


Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testinput2    2009-08-26 15:38:32 UTC (rev 426)
@@ -2773,4 +2773,143 @@
 /^X(?7)(a)(?|(b|(?|(r)|(t))(s))|(q))(c)(d)(Y)/
     XYabcdY


+/Xa{2,4}b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/Xa{2,4}?b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/Xa{2,4}+b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\d{2,4}b/
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+    
+/X\d{2,4}?b/
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+    
+/X\d{2,4}+b/
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+    
+/X\D{2,4}b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\D{2,4}?b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\D{2,4}+b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[abc]{2,4}b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[abc]{2,4}?b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[abc]{2,4}+b/
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[^a]{2,4}b/
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+    
+/X[^a]{2,4}?b/
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+    
+/X[^a]{2,4}+b/
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+    
+/(Y)X\1{2,4}b/
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+    
+/(Y)X\1{2,4}?b/
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+    
+/(Y)X\1{2,4}+b/
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+    
+/\++\KZ|\d+X|9+Y/
+    ++++123999\P
+    ++++123999Y\P
+    ++++Z1234\P 
+
+/Z(*F)/
+    Z\P
+    ZA\P 
+    
+/Z(?!)/
+    Z\P 
+    ZA\P 
+
 / End of testinput2 /


Modified: code/trunk/testdata/testinput5
===================================================================
--- code/trunk/testdata/testinput5    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testinput5    2009-08-26 15:38:32 UTC (rev 426)
@@ -485,4 +485,256 @@


/(*CRLF)(*UTF8)(*BSR_UNICODE)a\Rb/I

+/Xa{2,4}b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/Xa{2,4}?b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/Xa{2,4}+b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\x{123}{2,4}b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X\x{123}{2,4}?b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X\x{123}{2,4}+b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X\x{123}{2,4}b/8
+    Xx\P
+    X\x{123}x\P
+    X\x{123}\x{123}x\P 
+    X\x{123}\x{123}\x{123}x\P
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+    
+/X\x{123}{2,4}?b/8
+    Xx\P
+    X\x{123}x\P
+    X\x{123}\x{123}x\P 
+    X\x{123}\x{123}\x{123}x\P
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+    
+/X\x{123}{2,4}+b/8
+    Xx\P
+    X\x{123}x\P
+    X\x{123}\x{123}x\P 
+    X\x{123}\x{123}\x{123}x\P
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+    
+/X\d{2,4}b/8
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+    
+/X\d{2,4}?b/8
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+    
+/X\d{2,4}+b/8
+    X\P
+    X3\P
+    X33\P 
+    X333\P
+    X3333\P 
+
+/X\D{2,4}b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\D{2,4}?b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X\D{2,4}+b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+
+/X\D{2,4}b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X\D{2,4}?b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X\D{2,4}+b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+
+/X[abc]{2,4}b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[abc]{2,4}?b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+    
+/X[abc]{2,4}+b/8
+    X\P
+    Xa\P
+    Xaa\P 
+    Xaaa\P
+    Xaaaa\P 
+
+/X[abc\x{123}]{2,4}b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X[abc\x{123}]{2,4}?b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X[abc\x{123}]{2,4}+b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+
+/X[^a]{2,4}b/8
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+    
+/X[^a]{2,4}?b/8
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+    
+/X[^a]{2,4}+b/8
+    X\P
+    Xz\P
+    Xzz\P 
+    Xzzz\P
+    Xzzzz\P 
+
+/X[^a]{2,4}b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X[^a]{2,4}?b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/X[^a]{2,4}+b/8
+    X\P
+    X\x{123}\P
+    X\x{123}\x{123}\P 
+    X\x{123}\x{123}\x{123}\P
+    X\x{123}\x{123}\x{123}\x{123}\P 
+
+/(Y)X\1{2,4}b/8
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+    
+/(Y)X\1{2,4}?b/8
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+    
+/(Y)X\1{2,4}+b/8
+    YX\P
+    YXY\P
+    YXYY\P 
+    YXYYY\P
+    YXYYYY\P 
+
+/(\x{123})X\1{2,4}b/8
+    \x{123}X\P
+    \x{123}X\x{123}\P
+    \x{123}X\x{123}\x{123}\P 
+    \x{123}X\x{123}\x{123}\x{123}\P
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/(\x{123})X\1{2,4}?b/8
+    \x{123}X\P
+    \x{123}X\x{123}\P
+    \x{123}X\x{123}\x{123}\P 
+    \x{123}X\x{123}\x{123}\x{123}\P
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+    
+/(\x{123})X\1{2,4}+b/8
+    \x{123}X\P
+    \x{123}X\x{123}\P
+    \x{123}X\x{123}\x{123}\P 
+    \x{123}X\x{123}\x{123}\x{123}\P
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+
 / End of testinput5 /


Modified: code/trunk/testdata/testinput7
===================================================================
--- code/trunk/testdata/testinput7    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testinput7    2009-08-26 15:38:32 UTC (rev 426)
@@ -4421,4 +4421,16 @@
     "ab"
     \C-"ab"


+/\d+X|9+Y/
+    ++++123999\P
+    ++++123999Y\P
+
+/Z(*F)/
+    Z\P
+    ZA\P 
+    
+/Z(?!)/
+    Z\P 
+    ZA\P 
+
 / End of testinput7 /


Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testoutput2    2009-08-26 15:38:32 UTC (rev 426)
@@ -40,28 +40,24 @@


/a+bc/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'c'

/a*bc/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = 'c'

/a{3}bc/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'c'

/(abc|a+z)/I
Capturing subpattern count = 1
-Partial matching not supported
No options
First char = 'a'
No need char
@@ -113,14 +109,12 @@

/.*b/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char at start or follows newline
Need char = 'b'

/.*?b/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char at start or follows newline
Need char = 'b'
@@ -324,7 +318,6 @@

/.*((abc)$|(def))/I
Capturing subpattern count = 3
-Partial matching not supported
No options
First char at start or follows newline
No need char
@@ -401,7 +394,6 @@

/[^aeiou ]{3,}/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -410,7 +402,6 @@

/<.*>/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = '<'
Need char = '>'
@@ -419,7 +410,6 @@

/<.*?>/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = '<'
Need char = '>'
@@ -428,7 +418,6 @@

/<.*>/IU
Capturing subpattern count = 0
-Partial matching not supported
Options: ungreedy
First char = '<'
Need char = '>'
@@ -437,7 +426,6 @@

/(?U)<.*>/I
Capturing subpattern count = 0
-Partial matching not supported
Options: ungreedy
First char = '<'
Need char = '>'
@@ -446,7 +434,6 @@

/<.*?>/IU
Capturing subpattern count = 0
-Partial matching not supported
Options: ungreedy
First char = '<'
Need char = '>'
@@ -455,7 +442,6 @@

/={3,}/IU
Capturing subpattern count = 0
-Partial matching not supported
Options: ungreedy
First char = '='
Need char = '='
@@ -464,7 +450,6 @@

/(?U)={3,}?/I
Capturing subpattern count = 0
-Partial matching not supported
Options: ungreedy
First char = '='
Need char = '='
@@ -522,7 +507,6 @@

/(?s).*/I
Capturing subpattern count = 0
-Partial matching not supported
Options: anchored dotall
No first char
No need char
@@ -584,7 +568,6 @@
/((?s)blah)\s+\1/I
Capturing subpattern count = 1
Max back reference = 1
-Partial matching not supported
No options
First char = 'b'
Need char = 'h'
@@ -592,7 +575,6 @@
/((?i)blah)\s+\1/I
Capturing subpattern count = 1
Max back reference = 1
-Partial matching not supported
No options
First char = 'b' (caseless)
Need char = 'h' (caseless)
@@ -616,7 +598,6 @@

/(a*b|(?i:c*(?-i)d))/IS
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -668,7 +649,6 @@

/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/I
Capturing subpattern count = 5
-Partial matching not supported
Options: anchored
No first char
No need char
@@ -784,7 +764,6 @@

/(?>.*)(?<=(abcd)|(xyz))/I
Capturing subpattern count = 2
-Partial matching not supported
No options
First char at start or follows newline
No need char
@@ -1003,7 +982,6 @@

/(.{20})/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -1021,7 +999,6 @@

/(.{15})/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -1036,7 +1013,6 @@

 /(.{16})/I
 Capturing subpattern count = 1
-Partial matching not supported
 No options
 No first char
 No need char
@@ -1103,7 +1079,6 @@
 )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+
 )?)?)?)?)?)?)?)?)?otherword/I
 Capturing subpattern count = 8
-Partial matching not supported
 Contains explicit CR or LF match
 No options
 First char = 'w'
@@ -1118,7 +1093,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 First char at start or follows newline
 Need char = 'X'
@@ -1132,7 +1106,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored dotall
 No first char
 Need char = 'X'
@@ -1151,7 +1124,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 No options
 First char at start or follows newline
 No need char
@@ -1170,7 +1142,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: anchored dotall
 No first char
 No need char
@@ -1189,7 +1160,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: anchored dotall
 No first char
 No need char
@@ -1211,7 +1181,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 No need char
@@ -1296,7 +1265,6 @@


/.*iss/Ig+
Capturing subpattern count = 0
-Partial matching not supported
No options
First char at start or follows newline
Need char = 's'
@@ -1399,42 +1367,36 @@

/a*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char

/a+/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char

/(baa|a+)/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
Need char = 'a'

/a{0,3}/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char

/baa{3,}/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'b'
Need char = 'a'

/"([^\\"]+|\\.)*"/I
Capturing subpattern count = 1
-Partial matching not supported
No options
First char = '"'
Need char = '"'
@@ -1489,70 +1451,60 @@

/abc*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'

/ab.c*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'

/a.c*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char

/.c*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char

/ac*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char

/(a.c*|b.c*)/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char

/a.c*|aba/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char

/.+a/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = 'a'

/(?=abcda)a.*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'a'

/(?=a)a.*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char
@@ -1565,14 +1517,12 @@

/a\d*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char

/ab\d*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -1591,7 +1541,6 @@

 /ab\d+/I
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 First char = 'a'
 Need char = 'b'
@@ -1709,7 +1658,6 @@
   \)            # Closing )
   /Ix
 Capturing subpattern count = 0
-Partial matching not supported
 Options: extended
 First char = '('
 Need char = ')'
@@ -1738,7 +1686,6 @@


/\( ( (?>[^()]+) | (?R) )* \) /Ixg
Capturing subpattern count = 1
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1753,7 +1700,6 @@

/\( (?: (?>[^()]+) | (?R) ) \) /Ix
Capturing subpattern count = 0
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1772,7 +1718,6 @@

/\( (?: (?>[^()]+) | (?R) )? \) /Ix
Capturing subpattern count = 0
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1783,7 +1728,6 @@

/\( ( (?>[^()]+) | (?R) )* \) /Ix
Capturing subpattern count = 1
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1793,7 +1737,6 @@

/\( ( ( (?>[^()]+) | (?R) )* ) \) /Ix
Capturing subpattern count = 2
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1804,7 +1747,6 @@

/\( (123)? ( ( (?>[^()]+) | (?R) )* ) \) /Ix
Capturing subpattern count = 3
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1821,7 +1763,6 @@

/\( ( (123)? ( (?>[^()]+) | (?R) )* ) \) /Ix
Capturing subpattern count = 3
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1838,7 +1779,6 @@

/\( (((((((((( ( (?>[^()]+) | (?R) )* )))))))))) \) /Ix
Capturing subpattern count = 11
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1858,7 +1798,6 @@

/\( ( ( (?>[^()<>]+) | ((?>[^()]+)) | (?R) )* ) \) /Ix
Capturing subpattern count = 3
-Partial matching not supported
Options: extended
First char = '('
Need char = ')'
@@ -1870,7 +1809,6 @@

 /\( ( ( (?>[^()]+) | ((?R)) )* ) \) /Ix
 Capturing subpattern count = 3
-Partial matching not supported
 Options: extended
 First char = '('
 Need char = ')'
@@ -2249,7 +2187,6 @@
 /(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\w+)\s+(\270)/I
 Capturing subpattern count = 271
 Max back reference = 270
-Partial matching not supported
 No options
 No first char
 No need char
@@ -2930,7 +2867,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 No first char
 No need char
@@ -2959,7 +2895,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 First char = 'x'
 No need char
@@ -2975,7 +2910,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 First char = 'x'
 No need char
@@ -2999,7 +2933,6 @@


/^(\w++|\s++)*$/I
Capturing subpattern count = 1
-Partial matching not supported
Options: anchored
No first char
No need char
@@ -3013,7 +2946,6 @@

/(\d++)(\w)/I
Capturing subpattern count = 2
-Partial matching not supported
No options
No first char
No need char
@@ -3028,7 +2960,6 @@

/a++b/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -3037,7 +2968,6 @@

/(a++b)/I
Capturing subpattern count = 1
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -3047,7 +2977,6 @@

/(a++)b/I
Capturing subpattern count = 1
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -3057,7 +2986,6 @@

/([^()]++|\([^()]*\))+/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -3067,7 +2995,6 @@

 /\(([^()]++|\([^()]+\))+\)/I
 Capturing subpattern count = 1
-Partial matching not supported
 No options
 First char = '('
 Need char = ')'
@@ -3130,7 +3057,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 First char = 'x'
 Need char = 'b'
@@ -3147,7 +3073,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: ungreedy
 First char = 'x'
 Need char = 'b'
@@ -3176,7 +3101,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 5
-Partial matching not supported
 Options: anchored
 No first char
 No need char
@@ -3192,7 +3116,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'b'
@@ -3210,7 +3133,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'b'
@@ -3286,7 +3208,6 @@


/< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >/Ix
Capturing subpattern count = 0
-Partial matching not supported
Options: extended
First char = '<'
Need char = '>'
@@ -3336,14 +3257,12 @@
/(.*)\d+\1/I
Capturing subpattern count = 1
Max back reference = 1
-Partial matching not supported
No options
No first char
No need char

/(.*)\d+/I
Capturing subpattern count = 1
-Partial matching not supported
No options
First char at start or follows newline
No need char
@@ -3351,14 +3270,12 @@
/(.*)\d+\1/Is
Capturing subpattern count = 1
Max back reference = 1
-Partial matching not supported
Options: dotall
No first char
No need char

/(.*)\d+/Is
Capturing subpattern count = 1
-Partial matching not supported
Options: anchored dotall
No first char
No need char
@@ -3366,7 +3283,6 @@
/(.*(xyz))\d+\2/I
Capturing subpattern count = 2
Max back reference = 2
-Partial matching not supported
No options
First char at start or follows newline
Need char = 'z'
@@ -3374,7 +3290,6 @@
/((.*))\d+\1/I
Capturing subpattern count = 2
Max back reference = 1
-Partial matching not supported
No options
No first char
No need char
@@ -3391,7 +3306,6 @@

/(?=a).*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char = 'a'
No need char
@@ -3713,7 +3627,6 @@

/(\d{3}(?C))*/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -3842,7 +3755,6 @@

/a(b+)(c*)(?C1)/I
Capturing subpattern count = 2
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -3868,7 +3780,6 @@

/a(b+?)(c*?)(?C1)/I
Capturing subpattern count = 2
-Partial matching not supported
No options
First char = 'a'
Need char = 'b'
@@ -4031,7 +3942,6 @@
/^\W*(?:((.)\W*(?1)\W*\2|)|((.)\W*(?3)\W*\4|\W*.\W*))\W*$/Ii
Capturing subpattern count = 4
Max back reference = 4
-Partial matching not supported
Options: anchored caseless
No first char
No need char
@@ -4064,7 +3974,6 @@

/^(\d+|\((?1)([+*-])(?1)\)|-(?1))$/I
Capturing subpattern count = 2
-Partial matching not supported
Options: anchored
No first char
No need char
@@ -4105,7 +4014,6 @@

 /((< (?: (?(R) \d++  | [^<>]*+) | (?2)) * >))/Ix
 Capturing subpattern count = 2
-Partial matching not supported
 Options: extended
 First char = '<'
 Need char = '>'
@@ -4279,7 +4187,6 @@
   one     1
   three   3
   two     2
-Partial matching not supported
 Options: anchored caseless
 No first char
 No need char
@@ -4325,7 +4232,6 @@


/(.*)a/Is
Capturing subpattern count = 1
-Partial matching not supported
Options: anchored dotall
No first char
Need char = 'a'
@@ -4333,7 +4239,6 @@
/(.*)a\1/Is
Capturing subpattern count = 1
Max back reference = 1
-Partial matching not supported
Options: dotall
No first char
Need char = 'a'
@@ -4341,14 +4246,12 @@
/(.*)a(b)\2/Is
Capturing subpattern count = 2
Max back reference = 2
-Partial matching not supported
Options: anchored dotall
No first char
Need char = 'b'

/((.*)a|(.*)b)z/Is
Capturing subpattern count = 3
-Partial matching not supported
Options: anchored dotall
No first char
Need char = 'z'
@@ -4356,7 +4259,6 @@
/((.*)a|(.*)b)z\1/Is
Capturing subpattern count = 3
Max back reference = 1
-Partial matching not supported
Options: dotall
No first char
Need char = 'z'
@@ -4364,7 +4266,6 @@
/((.*)a|(.*)b)z\2/Is
Capturing subpattern count = 3
Max back reference = 2
-Partial matching not supported
Options: dotall
No first char
Need char = 'z'
@@ -4372,7 +4273,6 @@
/((.*)a|(.*)b)z\3/Is
Capturing subpattern count = 3
Max back reference = 3
-Partial matching not supported
Options: dotall
No first char
Need char = 'z'
@@ -4380,14 +4280,12 @@
/((.*)a|^(.*)b)z\3/Is
Capturing subpattern count = 3
Max back reference = 3
-Partial matching not supported
Options: anchored dotall
No first char
Need char = 'z'

/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a/Is
Capturing subpattern count = 31
-Partial matching not supported
Options: anchored dotall
No first char
No need char
@@ -4395,7 +4293,6 @@
/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\31/Is
Capturing subpattern count = 31
Max back reference = 31
-Partial matching not supported
Options: dotall
No first char
No need char
@@ -4403,7 +4300,6 @@
/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\32/Is
Capturing subpattern count = 32
Max back reference = 32
-Partial matching not supported
Options: dotall
No first char
No need char
@@ -4470,7 +4366,6 @@

/(a+)*zz/I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
Need char = 'z'
@@ -4607,7 +4502,6 @@
Capturing subpattern count = 3
Named capturing subpatterns:
elem 2
-Partial matching not supported
No options
First char = '['
Need char = ']'
@@ -4625,7 +4519,6 @@
Capturing subpattern count = 3
Named capturing subpatterns:
elem 2
-Partial matching not supported
No options
First char = '['
Need char = ']'
@@ -4732,7 +4625,6 @@

/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/Ii
Capturing subpattern count = 3
-Partial matching not supported
Options: caseless
No first char
Need char = 'g' (caseless)
@@ -4742,7 +4634,6 @@

 /((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/IiS
 Capturing subpattern count = 3
-Partial matching not supported
 Options: caseless
 No first char
 Need char = 'g' (caseless)
@@ -4761,7 +4652,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 No first char
 Need char = 'b'
@@ -4854,7 +4744,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options:
 No first char
 Need char = 'b'
@@ -4899,7 +4788,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options:
 First char = 'a'
 Need char = 'b'
@@ -5337,7 +5225,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options:
 No first char
 Need char = '3'
@@ -5369,7 +5256,6 @@


/\b.*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -5378,7 +5264,6 @@

/\b.*/Is
Capturing subpattern count = 0
-Partial matching not supported
Options: dotall
No first char
No need char
@@ -5387,7 +5272,6 @@

 /(?!.bcd).*/I
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 No first char
 No need char
@@ -5400,15 +5284,15 @@
 First char = 'a'
 Need char = 'e'
     ab\P
-Partial match
+Partial match: ab
     abc\P
-Partial match
+Partial match: abc
     abcd\P
-Partial match
+Partial match: abcd
     abcde\P
  0: abcde
     the quick brown abc\P
-Partial match
+Partial match: abc
     ** Failers\P
 No match
     the quick brown abxyz fox\P
@@ -5433,23 +5317,23 @@
  1: 02
  2: 05
     1\P
-Partial match
+Partial match: 1
     1/2\P
-Partial match
+Partial match: 1/2
     1/2/0\P
-Partial match
+Partial match: 1/2/0
     1/2/04\P
  0: 1/2/04
  1: 1
  2: 2
     0\P
-Partial match
+Partial match: 0
     02/\P
-Partial match
+Partial match: 02/
     02/0\P
-Partial match
+Partial match: 02/0
     02/1\P
-Partial match
+Partial match: 02/1
     ** Failers\P
 No match
     \P
@@ -5471,28 +5355,24 @@


/0{0,2}ABC/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = 'C'

/\d{3,}ABC/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = 'C'

/\d*ABC/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = 'C'

 /[abc]+DE/I
 Capturing subpattern count = 0
-Partial matching not supported
 No options
 No first char
 Need char = 'E'
@@ -5505,13 +5385,13 @@
     123\P
  0: 123
     a\P
-Partial match
+Partial match: a
     b\P
-Partial match
+Partial match: b
     c\P
-Partial match
+Partial match: c
     c12\P
-Partial match
+Partial match: c12
     c123\P
  0: c123


@@ -5521,17 +5401,17 @@
 No first char
 Need char = 'X'
     1\P
-Partial match
+Partial match: 1
     123\P
-Partial match
+Partial match: 123
     123X
  0: 123X
     1234\P
-Partial match
+Partial match: 1234
     1234X
  0: 1234X
     12345\P
-Partial match
+Partial match: 12345
     12345X
  0: 12345X
     *** Failers
@@ -5616,7 +5496,6 @@
 ~<(\w+)/?>(.)*</(\1)>~smgI
 Capturing subpattern count = 3
 Max back reference = 1
-Partial matching not supported
 Options: multiline dotall
 First char = '<'
 Need char = '>'
@@ -5923,7 +5802,6 @@


/[^()]*(?:\((?R)\)[^()]*)*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -5936,7 +5814,6 @@

/[^()]*(?:\((?>(?R))\)[^()]*)*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -5947,7 +5824,6 @@

/[^()]*(?:\((?R)\))*[^()]*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -5958,7 +5834,6 @@

/(?:\((?R)\))*[^()]*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -5971,7 +5846,6 @@

/(?:\((?R)\))|[^()]*/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char
@@ -6313,7 +6187,6 @@

/\s*,\s*/IS
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
Need char = ','
@@ -6443,7 +6316,6 @@

/.*/I<lf>
Capturing subpattern count = 0
-Partial matching not supported
Options:
Forced newline sequence: LF
First char at start or follows newline
@@ -6469,7 +6341,6 @@

/\w+(.)(.)?def/Is
Capturing subpattern count = 2
-Partial matching not supported
Options: dotall
No first char
Need char = 'f'
@@ -6486,7 +6357,6 @@

+((?:\s|//.*\\n|/[*](?:\\n|.)*?[*]/)*)+I
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -6621,7 +6491,6 @@

 /(a*b|(?i:c*(?-i)d))/IS
 Capturing subpattern count = 1
-Partial matching not supported
 No options
 No first char
 No need char
@@ -6680,7 +6549,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'b'
@@ -6696,7 +6564,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'b'
@@ -6712,7 +6579,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'b'
@@ -6728,7 +6594,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored
 No first char
 Need char = 'A'
@@ -6750,7 +6615,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: anchored caseless
 No first char
 Need char = 'A' (caseless)
@@ -6761,7 +6625,6 @@


/(a*|b*)[cd]/IS
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -6769,7 +6632,6 @@

/(a+|b*)[cd]/IS
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -6777,7 +6639,6 @@

/(a*|b+)[cd]/IS
Capturing subpattern count = 1
-Partial matching not supported
No options
No first char
No need char
@@ -6785,7 +6646,6 @@

 /(a+|b+)[cd]/IS
 Capturing subpattern count = 1
-Partial matching not supported
 No options
 No first char
 No need char
@@ -7660,7 +7520,6 @@
   one     1
   three   3
   two     2
-Partial matching not supported
 Options: anchored caseless
 No first char
 No need char
@@ -7694,7 +7553,6 @@
 /(?=(\w+))\1:/I
 Capturing subpattern count = 1
 Max back reference = 1
-Partial matching not supported
 No options
 No first char
 Need char = ':'
@@ -7707,7 +7565,6 @@
 Max back reference = 1
 Named capturing subpatterns:
   abc   1
-Partial matching not supported
 No options
 No first char
 Need char = ':'
@@ -9216,7 +9073,6 @@


/a\R{2,4}b/I<bsr_anycrlf>
Capturing subpattern count = 0
-Partial matching not supported
Options: bsr_anycrlf
First char = 'a'
Need char = 'b'
@@ -9235,7 +9091,6 @@

/a\R{2,4}b/I<bsr_unicode>
Capturing subpattern count = 0
-Partial matching not supported
Options: bsr_unicode
First char = 'a'
Need char = 'b'
@@ -9640,7 +9495,6 @@

/(?(?=.*b)b|^)/CI
Capturing subpattern count = 0
-Partial matching not supported
Options:
No first char
No need char
@@ -9680,14 +9534,12 @@

/(?(?=b).*b|^d)/I
Capturing subpattern count = 0
-Partial matching not supported
No options
No first char
No need char

/(?(?=.*b).*b|^d)/I
Capturing subpattern count = 0
-Partial matching not supported
No options
First char at start or follows newline
No need char
@@ -9840,4 +9692,240 @@
6: d
7: Y

+/Xa{2,4}b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/Xa{2,4}?b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/Xa{2,4}+b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\d{2,4}b/
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+    
+/X\d{2,4}?b/
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+    
+/X\d{2,4}+b/
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+    
+/X\D{2,4}b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\D{2,4}?b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\D{2,4}+b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[abc]{2,4}b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[abc]{2,4}?b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[abc]{2,4}+b/
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[^a]{2,4}b/
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+    
+/X[^a]{2,4}?b/
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+    
+/X[^a]{2,4}+b/
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+    
+/(Y)X\1{2,4}b/
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+    
+/(Y)X\1{2,4}?b/
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+    
+/(Y)X\1{2,4}+b/
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+    
+/\++\KZ|\d+X|9+Y/
+    ++++123999\P
+Partial match: 123999
+    ++++123999Y\P
+ 0: 999Y
+    ++++Z1234\P 
+ 0: Z
+
+/Z(*F)/
+    Z\P
+Partial match: Z
+    ZA\P 
+No match
+    
+/Z(?!)/
+    Z\P 
+Partial match: Z
+    ZA\P 
+No match
+
 / End of testinput2 /


Modified: code/trunk/testdata/testoutput5
===================================================================
--- code/trunk/testdata/testoutput5    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testoutput5    2009-08-26 15:38:32 UTC (rev 426)
@@ -252,7 +252,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 Need char = 'X'
@@ -269,7 +268,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -423,7 +421,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 196
 Need char = 128
@@ -443,7 +440,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -462,7 +458,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -481,7 +476,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -501,7 +495,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -551,7 +544,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -565,7 +557,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 'a'
 No need char
@@ -579,7 +570,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 'a'
 Need char = 'b'
@@ -593,7 +583,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 'a'
 Need char = 128
@@ -607,7 +596,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 'a'
 Need char = 129
@@ -621,7 +609,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 Need char = 'A'
@@ -640,7 +627,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1122,7 +1108,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1136,7 +1121,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1150,7 +1134,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1164,7 +1147,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1178,7 +1160,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1192,7 +1173,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char
@@ -1206,7 +1186,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 196
 Need char = 128
@@ -1220,7 +1199,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 196
 Need char = 'X'
@@ -1234,7 +1212,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 First char = 'X'
 Need char = 128
@@ -1652,4 +1629,436 @@
 First char = 'a'
 Need char = 'b'


+/Xa{2,4}b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/Xa{2,4}?b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/Xa{2,4}+b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\x{123}{2,4}b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X\x{123}{2,4}?b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X\x{123}{2,4}+b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X\x{123}{2,4}b/8
+    Xx\P
+No match
+    X\x{123}x\P
+No match
+    X\x{123}\x{123}x\P 
+No match
+    X\x{123}\x{123}\x{123}x\P
+No match
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+No match
+    
+/X\x{123}{2,4}?b/8
+    Xx\P
+No match
+    X\x{123}x\P
+No match
+    X\x{123}\x{123}x\P 
+No match
+    X\x{123}\x{123}\x{123}x\P
+No match
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+No match
+    
+/X\x{123}{2,4}+b/8
+    Xx\P
+No match
+    X\x{123}x\P
+No match
+    X\x{123}\x{123}x\P 
+No match
+    X\x{123}\x{123}\x{123}x\P
+No match
+    X\x{123}\x{123}\x{123}\x{123}x\P 
+No match
+    
+/X\d{2,4}b/8
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+    
+/X\d{2,4}?b/8
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+    
+/X\d{2,4}+b/8
+    X\P
+Partial match: X
+    X3\P
+Partial match: X3
+    X33\P 
+Partial match: X33
+    X333\P
+Partial match: X333
+    X3333\P 
+Partial match: X3333
+
+/X\D{2,4}b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\D{2,4}?b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X\D{2,4}+b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+
+/X\D{2,4}b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X\D{2,4}?b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X\D{2,4}+b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+
+/X[abc]{2,4}b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[abc]{2,4}?b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+    
+/X[abc]{2,4}+b/8
+    X\P
+Partial match: X
+    Xa\P
+Partial match: Xa
+    Xaa\P 
+Partial match: Xaa
+    Xaaa\P
+Partial match: Xaaa
+    Xaaaa\P 
+Partial match: Xaaaa
+
+/X[abc\x{123}]{2,4}b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X[abc\x{123}]{2,4}?b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X[abc\x{123}]{2,4}+b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+
+/X[^a]{2,4}b/8
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+    
+/X[^a]{2,4}?b/8
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+    
+/X[^a]{2,4}+b/8
+    X\P
+Partial match: X
+    Xz\P
+Partial match: Xz
+    Xzz\P 
+Partial match: Xzz
+    Xzzz\P
+Partial match: Xzzz
+    Xzzzz\P 
+Partial match: Xzzzz
+
+/X[^a]{2,4}b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X[^a]{2,4}?b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+    
+/X[^a]{2,4}+b/8
+    X\P
+Partial match: X
+    X\x{123}\P
+Partial match: X\x{123}
+    X\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\P
+Partial match: X\x{123}\x{123}\x{123}
+    X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: X\x{123}\x{123}\x{123}\x{123}
+
+/(Y)X\1{2,4}b/8
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+    
+/(Y)X\1{2,4}?b/8
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+    
+/(Y)X\1{2,4}+b/8
+    YX\P
+Partial match: YX
+    YXY\P
+Partial match: YXY
+    YXYY\P 
+Partial match: YXYY
+    YXYYY\P
+Partial match: YXYYY
+    YXYYYY\P 
+Partial match: YXYYYY
+
+/(\x{123})X\1{2,4}b/8
+    \x{123}X\P
+Partial match: \x{123}X
+    \x{123}X\x{123}\P
+Partial match: \x{123}X\x{123}
+    \x{123}X\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\P
+Partial match: \x{123}X\x{123}\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}\x{123}\x{123}
+    
+/(\x{123})X\1{2,4}?b/8
+    \x{123}X\P
+Partial match: \x{123}X
+    \x{123}X\x{123}\P
+Partial match: \x{123}X\x{123}
+    \x{123}X\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\P
+Partial match: \x{123}X\x{123}\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}\x{123}\x{123}
+    
+/(\x{123})X\1{2,4}+b/8
+    \x{123}X\P
+Partial match: \x{123}X
+    \x{123}X\x{123}\P
+Partial match: \x{123}X\x{123}
+    \x{123}X\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\P
+Partial match: \x{123}X\x{123}\x{123}\x{123}
+    \x{123}X\x{123}\x{123}\x{123}\x{123}\P 
+Partial match: \x{123}X\x{123}\x{123}\x{123}\x{123}
+
 / End of testinput5 /


Modified: code/trunk/testdata/testoutput6
===================================================================
--- code/trunk/testdata/testoutput6    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testoutput6    2009-08-26 15:38:32 UTC (rev 426)
@@ -630,7 +630,6 @@
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 0
-Partial matching not supported
 Options: utf8
 No first char
 No need char


Modified: code/trunk/testdata/testoutput7
===================================================================
--- code/trunk/testdata/testoutput7    2009-08-17 14:48:48 UTC (rev 425)
+++ code/trunk/testdata/testoutput7    2009-08-26 15:38:32 UTC (rev 426)
@@ -7168,7 +7168,6 @@


/a\R{2,4}b/I<bsr_anycrlf>
Capturing subpattern count = 0
-Partial matching not supported
Options: bsr_anycrlf
First char = 'a'
Need char = 'b'
@@ -7187,7 +7186,6 @@

 /a\R{2,4}b/I<bsr_unicode>
 Capturing subpattern count = 0
-Partial matching not supported
 Options: bsr_unicode
 First char = 'a'
 Need char = 'b'
@@ -7370,4 +7368,22 @@
     \C-"ab"
  0: "ab"


+/\d+X|9+Y/
+    ++++123999\P
+Partial match: 123999
+    ++++123999Y\P
+ 0: 999Y
+
+/Z(*F)/
+    Z\P
+Partial match: Z
+    ZA\P 
+No match
+    
+/Z(?!)/
+    Z\P 
+Partial match: Z
+    ZA\P 
+No match
+
 / End of testinput7 /