@@ -756,6 +756,7 @@ BOOL overflowed = FALSE;
756756BOOL use_existing_match ;
757757BOOL replacement_only ;
758758BOOL utf = (code -> overall_options & PCRE2_UTF ) != 0 ;
759+ BOOL partial = (options & (PCRE2_PARTIAL_HARD |PCRE2_PARTIAL_SOFT )) != 0 ;
759760PCRE2_UCHAR temp [6 ];
760761PCRE2_UCHAR null_str [1 ] = { 0xcd };
761762PCRE2_SPTR original_subject = subject ;
@@ -783,10 +784,16 @@ if (mcontext != NULL)
783784 substitute_case_callout_data = mcontext -> substitute_case_callout_data ;
784785 }
785786
786- /* Partial matching is not valid. This must come after setting *blength to
787- PCRE2_UNSET, so as not to imply an offset in the replacement. */
787+ /* Partial matching is supported, with limitations. We allow matching in partial
788+ mode, however, if a partial match is found, the substitution will fail with a
789+ PCRE2_ERROR_PARTIAL error. Additionally, outputting the after-match text is not
790+ allowed (PCRE2_ERROR_BADOPTION), and certain replacement items such as $' and $_
791+ are not supported (PCRE2_ERROR_PARTIALSUBS).
788792
789- if ((options & (PCRE2_PARTIAL_HARD |PCRE2_PARTIAL_SOFT )) != 0 )
793+ This must come after setting *blength to PCRE2_UNSET, so as not to imply an
794+ offset in the replacement. */
795+
796+ if (partial && (options & PCRE2_SUBSTITUTE_REPLACEMENT_ONLY ) == 0 )
790797 return PCRE2_ERROR_BADOPTION ;
791798
792799/* Validate length and find the end of the replacement. A NULL replacement of
@@ -1125,8 +1132,16 @@ for (;;)
11251132 if (next == CHAR_GRAVE_ACCENT || next == CHAR_APOSTROPHE )
11261133 {
11271134 ++ ptr ;
1135+
1136+ /* (Sanity-check ovector before reading from it.) */
11281137 rc = pcre2_substring_length_bynumber (match_data , 0 , & sublength );
1129- if (rc < 0 ) goto PTREXIT ; /* (Sanity-check ovector before reading from it.) */
1138+ /* LCOV_EXCL_START */
1139+ if (rc < 0 )
1140+ {
1141+ PCRE2_DEBUG_UNREACHABLE ();
1142+ goto PTREXIT ;
1143+ }
1144+ /* LCOV_EXCL_STOP */
11301145
11311146 if (next == CHAR_GRAVE_ACCENT )
11321147 {
@@ -1135,6 +1150,12 @@ for (;;)
11351150 }
11361151 else
11371152 {
1153+ if (partial )
1154+ {
1155+ rc = PCRE2_ERROR_PARTIALSUBS ;
1156+ goto PTREXIT ;
1157+ }
1158+
11381159 subptr = subject + ovector [1 ];
11391160 subptrend = subject + length ;
11401161 }
@@ -1145,12 +1166,19 @@ for (;;)
11451166 {
11461167 /* Java, .NET support $_ for "entire input string". */
11471168 ++ ptr ;
1169+
1170+ if (partial )
1171+ {
1172+ rc = PCRE2_ERROR_PARTIALSUBS ;
1173+ goto PTREXIT ;
1174+ }
1175+
11481176 subptr = subject ;
11491177 subptrend = subject + length ;
11501178 goto SUBPTR_SUBSTITUTE ;
11511179 }
1152- else if (next == CHAR_PLUS &&
1153- !(ptr + 1 < repend && ptr [1 ] == CHAR_LEFT_CURLY_BRACKET ))
1180+ if (next == CHAR_PLUS &&
1181+ !(ptr + 1 < repend && ptr [1 ] == CHAR_LEFT_CURLY_BRACKET ))
11541182 {
11551183 /* Perl supports $+ for "highest captured group" (not the same as $^N
11561184 which is mainly only useful inside Perl's match callbacks). We also
0 commit comments