Revision: 465
http://www.exim.org/viewvc/pcre2?view=rev&revision=465
Author: ph10
Date: 2015-12-12 18:45:40 +0000 (Sat, 12 Dec 2015)
Log Message:
-----------
Implement PCRE2_SUBSTITUTE_{OVERFLOW_LENGTH,UNKNOWN_UNSET}.
Modified Paths:
--------------
code/trunk/ChangeLog
code/trunk/doc/pcre2_substitute.3
code/trunk/doc/pcre2api.3
code/trunk/doc/pcre2test.1
code/trunk/src/pcre2.h
code/trunk/src/pcre2.h.in
code/trunk/src/pcre2_substitute.c
code/trunk/src/pcre2test.c
code/trunk/testdata/testinput2
code/trunk/testdata/testoutput2
Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/ChangeLog 2015-12-12 18:45:40 UTC (rev 465)
@@ -386,7 +386,10 @@
111. "Harden" pcre2test against ridiculously large values in modifiers and
command line arguments.
+112. Implemented PCRE2_SUBSTITUTE_UNKNOWN_UNSET and PCRE2_SUBSTITUTE_OVERFLOW_
+LENGTH.
+
Version 10.20 30-June-2015
--------------------------
Modified: code/trunk/doc/pcre2_substitute.3
===================================================================
--- code/trunk/doc/pcre2_substitute.3 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/doc/pcre2_substitute.3 2015-12-12 18:45:40 UTC (rev 465)
@@ -1,4 +1,4 @@
-.TH PCRE2_SUBSTITUTE 3 "04 December 2015" "PCRE2 10.21"
+.TH PCRE2_SUBSTITUTE 3 "12 December 2015" "PCRE2 10.21"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.SH SYNOPSIS
@@ -58,6 +58,8 @@
PCRE2_UTF was set at compile time)
PCRE2_SUBSTITUTE_EXTENDED Do extended replacement processing
PCRE2_SUBSTITUTE_GLOBAL Replace all occurrences in the subject
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH If overflow, compute needed length
+ PCRE2_SUBSTITUTE_UNKNOWN_UNSET Treat unknown group as unset
PCRE2_SUBSTITUTE_UNSET_EMPTY Simple unset insert = empty string
.sp
The function returns the number of substitutions, which may be zero if there
Modified: code/trunk/doc/pcre2api.3
===================================================================
--- code/trunk/doc/pcre2api.3 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/doc/pcre2api.3 2015-12-12 18:45:40 UTC (rev 465)
@@ -1,4 +1,4 @@
-.TH PCRE2API 3 "04 December 2015" "PCRE2 10.21"
+.TH PCRE2API 3 "12 December 2015" "PCRE2 10.21"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.sp
@@ -2704,13 +2704,21 @@
allocate memory for the compiled code.
.P
The \fIoutlengthptr\fP argument must point to a variable that contains the
-length, in code units, of the output buffer. If the function is successful,
-the value is updated to contain the length of the new string, excluding the
-trailing zero that is automatically added. If the function is not successful,
-the value is set to PCRE2_UNSET for general errors (such as output buffer too
-small). For syntax errors in the replacement string, the value is set to the
-offset in the replacement string where the error was detected.
+length, in code units, of the output buffer. If the function is successful, the
+value is updated to contain the length of the new string, excluding the
+trailing zero that is automatically added.
.P
+If the function is not successful, the value set via \fIoutlengthptr\fP depends
+on the type of error. For syntax errors in the replacement string, the value is
+the offset in the replacement string where the error was detected. For other
+errors, the value is PCRE2_UNSET by default. This includes the case of the
+output buffer being too small, unless PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set
+(see below), in which case the value is the minimum length needed, including
+space for the trailing zero. Note that in order to compute the required length,
+\fBpcre2_substitute()\fP has to simulate all the matching and copying, instead
+of giving an error return as soon as the buffer overflows. Note also that the
+length is in code units, not bytes.
+.P
In the replacement string, which is interpreted as a UTF string in UTF mode,
and is checked for UTF validity unless the PCRE2_NO_UTF_CHECK option is set, a
dollar character is an escape character that can specify the insertion of
@@ -2734,7 +2742,8 @@
apple lemon
2: pear orange
.sp
-Three additional options are available:
+As well as the usual options for \fBpcre2_match()\fP, a number of additional
+options can be set in the \fIoptions\fP argument.
.P
PCRE2_SUBSTITUTE_GLOBAL causes the function to iterate over the subject string,
replacing every matching substring. If this is not set, only the first matching
@@ -2745,11 +2754,31 @@
next two characters are CR, LF. In this case, the current position is advanced
by two characters.
.P
-PCRE2_SUBSTITUTE_UNSET_EMPTY causes unset capturing groups to be treated as
-empty strings when inserted as described above. If this option is not set, an
-attempt to insert an unset group causes the PCRE2_ERROR_UNSET error. This
-option does not influence the extended substitution syntax described below.
+PCRE2_SUBSTITUTE_OVERFLOW_LENGTH changes what happens when the output buffer is
+too small. The default action is to return PCRE2_ERROR_NOMEMORY immediately. If
+this option is set, however, \fBpcre2_substitute()\fP continues to go through
+the motions of matching and substituting (without, of course, writing anything)
+in order to compute the size of buffer that is needed. This value is passed
+back via the \fIoutlengthptr\fP variable, with the result of the function still
+being PCRE2_ERROR_NOMEMORY.
.P
+Passing a buffer size of zero is a permitted way of finding out how much memory
+is needed for given substitution. However, this does mean that the entire
+operation is carried out twice. Depending on the application, it may be more
+efficient to allocate a large buffer and free the excess afterwards, instead of
+using PCRE2_SUBSTITUTE_OVERFLOW_LENGTH.
+.P
+PCRE2_SUBSTITUTE_UNKNOWN_UNSET causes references to capturing groups that do
+not appear in the pattern to be treated as unset groups. This option should be
+used with care, because it means that a typo in a group name or number no
+longer causes the PCRE2_ERROR_NOSUBSTRING error.
+.P
+PCRE2_SUBSTITUTE_UNSET_EMPTY causes unset capturing groups (including unknown
+groups when PCRE2_SUBSTITUTE_UNKNOWN_UNSET is set) to be treated as empty
+strings when inserted as described above. If this option is not set, an attempt
+to insert an unset group causes the PCRE2_ERROR_UNSET error. This option does
+not influence the extended substitution syntax described below.
+.P
PCRE2_SUBSTITUTE_EXTENDED causes extra processing to be applied to the
replacement string. Without this option, only the dollar character is special,
and only the group insertion forms listed above are valid. When
@@ -2800,26 +2829,38 @@
1: HELLO
.sp
The PCRE2_SUBSTITUTE_UNSET_EMPTY option does not affect these extended
-substitutions.
+substitutions. However, PCRE2_SUBSTITUTE_UNKNOWN_UNSET does cause unknown
+groups in the extended syntax forms to be treated as unset.
.P
-If successful, the function returns the number of replacements that were made.
-This may be zero if no matches were found, and is never greater than 1 unless
-PCRE2_SUBSTITUTE_GLOBAL is set.
+If successful, \fBpcre2_substitute()\fP returns the number of replacements that
+were made. This may be zero if no matches were found, and is never greater than
+1 unless PCRE2_SUBSTITUTE_GLOBAL is set.
.P
In the event of an error, a negative error code is returned. Except for
PCRE2_ERROR_NOMATCH (which is never returned), errors from \fBpcre2_match()\fP
-are passed straight back. PCRE2_ERROR_NOSUBSTRING is returned for a
-non-existent substring insertion, and PCRE2_ERROR_UNSET is returned for an
-unset substring insertion when the simple (non-extended) syntax is used and
-PCRE2_SUBSTITUTE_UNSET_EMPTY is not set. PCRE2_ERROR_NOMEMORY is returned if
-the output buffer is not big enough. PCRE2_ERROR_BADREPLACEMENT is used for
-miscellaneous syntax errors in the replacement string, with more particular
-errors being PCRE2_ERROR_BADREPESCAPE (invalid escape sequence),
-PCRE2_ERROR_REPMISSING_BRACE (closing curly bracket not found),
-PCRE2_BADSUBSTITUTION (syntax error in extended group substitution), and
-PCRE2_BADSUBPATTERN (the pattern match ended before it started). As for all
-PCRE2 errors, a text message that describes the error can be obtained by
-calling \fBpcre2_get_error_message()\fP.
+are passed straight back.
+.P
+PCRE2_ERROR_NOSUBSTRING is returned for a non-existent substring insertion,
+unless PCRE2_SUBSTITUTE_UNKNOWN_UNSET is set.
+.P
+PCRE2_ERROR_UNSET is returned for an unset substring insertion (including an
+unknown substring when PCRE2_SUBSTITUTE_UNKNOWN_UNSET is set) when the simple
+(non-extended) syntax is used and PCRE2_SUBSTITUTE_UNSET_EMPTY is not set.
+.P
+PCRE2_ERROR_NOMEMORY is returned if the output buffer is not big enough. If the
+PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set, the size of buffer that is
+needed is returned via \fIoutlengthptr\fP. Note that this does not happen by
+default.
+.P
+PCRE2_ERROR_BADREPLACEMENT is used for miscellaneous syntax errors in the
+replacement string, with more particular errors being PCRE2_ERROR_BADREPESCAPE
+(invalid escape sequence), PCRE2_ERROR_REPMISSING_BRACE (closing curly bracket
+not found), PCRE2_BADSUBSTITUTION (syntax error in extended group
+substitution), and PCRE2_BADSUBPATTERN (the pattern match ended before it
+started, which can happen if \eK is used in an assertion).
+.P
+As for all PCRE2 errors, a text message that describes the error can be
+obtained by calling \fBpcre2_get_error_message()\fP.
.
.
.SH "DUPLICATE SUBPATTERN NAMES"
@@ -3113,6 +3154,6 @@
.rs
.sp
.nf
-Last updated: 04 December 2015
+Last updated: 21 December 2015
Copyright (c) 1997-2015 University of Cambridge.
.fi
Modified: code/trunk/doc/pcre2test.1
===================================================================
--- code/trunk/doc/pcre2test.1 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/doc/pcre2test.1 2015-12-12 18:45:40 UTC (rev 465)
@@ -1,4 +1,4 @@
-.TH PCRE2TEST 1 "04 December 2015" "PCRE 10.21"
+.TH PCRE2TEST 1 "12 December 2015" "PCRE 10.21"
.SH NAME
pcre2test - a program for testing Perl-compatible regular expressions.
.SH SYNOPSIS
@@ -854,16 +854,18 @@
not appear in \fB#pattern\fP commands. These modifiers do not affect the
compilation process.
.sp
- aftertext show text after match
- allaftertext show text after captures
- allcaptures show all captures
- allusedtext show all consulted text
- /g global global matching
- mark show mark values
- replace=<string> specify a replacement string
- startchar show starting character when relevant
- substitute_extended use PCRE2_SUBSTITUTE_EXTENDED
- substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY
+ aftertext show text after match
+ allaftertext show text after captures
+ allcaptures show all captures
+ allusedtext show all consulted text
+ /g global global matching
+ mark show mark values
+ replace=<string> specify a replacement string
+ startchar show starting character when relevant
+ substitute_extended use PCRE2_SUBSTITUTE_EXTENDED
+ substitute_overflow_length use PCRE2_SUBSTITUTE_OVERFLOW_LENGTH
+ substitute_unknown_unset use PCRE2_SUBSTITUTE_UNKNOWN_UNSET
+ substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY
.sp
These modifiers may not appear in a \fB#pattern\fP command. If you want them as
defaults, set them in a \fB#subject\fP command.
@@ -935,36 +937,38 @@
in which case they apply to every subject line that is matched against that
pattern.
.sp
- aftertext show text after match
- allaftertext show text after captures
- allcaptures show all captures
- allusedtext show all consulted text (non-JIT only)
- altglobal alternative global matching
- callout_capture show captures at callout time
- callout_data=<n> set a value to pass via callouts
- callout_fail=<n>[:<m>] control callout failure
- callout_none do not supply a callout function
- copy=<number or name> copy captured substring
- dfa use \fBpcre2_dfa_match()\fP
- find_limits find match and recursion limits
- get=<number or name> extract captured substring
- getall extract all captured substrings
- /g global global matching
- jitstack=<n> set size of JIT stack
- mark show mark values
- match_limit=<n> set a match limit
- memory show memory usage
- null_context match with a NULL context
- offset=<n> set starting offset
- offset_limit=<n> set offset limit
- ovector=<n> set size of output vector
- recursion_limit=<n> set a recursion limit
- replace=<string> specify a replacement string
- startchar show startchar when relevant
- startoffset=<n> same as offset=<n>
- substitute_extedded use PCRE2_SUBSTITUTE_EXTENDED
- substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY
- zero_terminate pass the subject as zero-terminated
+ aftertext show text after match
+ allaftertext show text after captures
+ allcaptures show all captures
+ allusedtext show all consulted text (non-JIT only)
+ altglobal alternative global matching
+ callout_capture show captures at callout time
+ callout_data=<n> set a value to pass via callouts
+ callout_fail=<n>[:<m>] control callout failure
+ callout_none do not supply a callout function
+ copy=<number or name> copy captured substring
+ dfa use \fBpcre2_dfa_match()\fP
+ find_limits find match and recursion limits
+ get=<number or name> extract captured substring
+ getall extract all captured substrings
+ /g global global matching
+ jitstack=<n> set size of JIT stack
+ mark show mark values
+ match_limit=<n> set a match limit
+ memory show memory usage
+ null_context match with a NULL context
+ offset=<n> set starting offset
+ offset_limit=<n> set offset limit
+ ovector=<n> set size of output vector
+ recursion_limit=<n> set a recursion limit
+ replace=<string> specify a replacement string
+ startchar show startchar when relevant
+ startoffset=<n> same as offset=<n>
+ substitute_extedded use PCRE2_SUBSTITUTE_EXTENDED
+ substitute_overflow_length use PCRE2_SUBSTITUTE_OVERFLOW_LENGTH
+ substitute_unknown_unset use PCRE2_SUBSTITUTE_UNKNOWN_UNSET
+ substitute_unset_empty use PCRE2_SUBSTITUTE_UNSET_EMPTY
+ zero_terminate pass the subject as zero-terminated
.sp
The effects of these modifiers are described in the following sections.
.
@@ -1107,10 +1111,15 @@
individual code units are copied directly. This provides a means of passing an
invalid UTF-8 string for testing purposes.
.P
-If the \fBglobal\fP modifier is set, PCRE2_SUBSTITUTE_GLOBAL is passed to
-\fBpcre2_substitute()\fP. The \fBsubstitute_extended\fP and
-\fBsubstitute_unset_empty\fP modifiers set PCRE2_SUBSTITUTE_EXTENDED and
-PCRE2_SUBSTITUTE_UNSET_EMPTY, respectively.
+The following modifiers set options (in additional to the normal match options)
+for \fBpcre2_substitute()\fP:
+.sp
+ global PCRE2_SUBSTITUTE_GLOBAL
+ substitute_extended PCRE2_SUBSTITUTE_EXTENDED
+ substitute_overflow_length PCRE2_SUBSTITUTE_OVERFLOW_LENGTH
+ substitute_unknown_unset PCRE2_SUBSTITUTE_UNKNOWN_UNSET
+ substitute_unset_empty PCRE2_SUBSTITUTE_UNSET_EMPTY
+.sp
.P
After a successful substitution, the modified string is output, preceded by the
number of replacements. This may be zero if there were no matches. Here is a
@@ -1135,6 +1144,19 @@
123abc123\e=replace=[9]XYZ
Failed: error -47: no more memory
.sp
+The default action of \fBpcre2_substitute()\fP is to return
+PCRE2_ERROR_NOMEMORY when the output buffer is too small. However, if the
+PCRE2_SUBSTITUTE_OVERFLOW_LENGTH option is set (by using the
+\fBsubstitute_overflow_length\fP modifier), \fBpcre2_substitute()\fP continues
+to go through the motions of matching and substituting, in order to compute the
+size of buffer that is required. When this happens, \fBpcre2test\fP shows the
+required buffer length (which includes space for the trailing zero) as part of
+the error message. For example:
+.sp
+ /abc/substitute_overflow_length
+ 123abc123\e=replace=[9]XYZ
+ Failed: error -47: no more memory: 10 code units are needed
+.sp
A replacement string is ignored with POSIX and DFA matching. Specifying partial
matching provokes an error return ("bad option value") from
\fBpcre2_substitute()\fP.
@@ -1618,6 +1640,6 @@
.rs
.sp
.nf
-Last updated: 04 December 2015
+Last updated: 12 December 2015
Copyright (c) 1997-2015 University of Cambridge.
.fi
Modified: code/trunk/src/pcre2.h
===================================================================
--- code/trunk/src/pcre2.h 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/src/pcre2.h 2015-12-12 18:45:40 UTC (rev 465)
@@ -148,9 +148,11 @@
/* These are additional options for pcre2_substitute(). */
-#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
-#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
-#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
+#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
+#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u
+#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u
/* Newline and \R settings, for use in compile contexts. The newline values
must be kept in step with values set in config.h and both sets must all be
Modified: code/trunk/src/pcre2.h.in
===================================================================
--- code/trunk/src/pcre2.h.in 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/src/pcre2.h.in 2015-12-12 18:45:40 UTC (rev 465)
@@ -148,9 +148,11 @@
/* These are additional options for pcre2_substitute(). */
-#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
-#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
-#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
+#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
+#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u
+#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u
/* Newline and \R settings, for use in compile contexts. The newline values
must be kept in step with values set in config.h and both sets must all be
Modified: code/trunk/src/pcre2_substitute.c
===================================================================
--- code/trunk/src/pcre2_substitute.c 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/src/pcre2_substitute.c 2015-12-12 18:45:40 UTC (rev 465)
@@ -47,7 +47,13 @@
#define PTR_STACK_SIZE 20
+#define SUBSTITUTE_OPTIONS \
+ (PCRE2_SUBSTITUTE_EXTENDED|PCRE2_SUBSTITUTE_GLOBAL| \
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH|PCRE2_SUBSTITUTE_UNKNOWN_UNSET| \
+ PCRE2_SUBSTITUTE_UNSET_EMPTY)
+
+
/*************************************************
* Find end of substitute text *
*************************************************/
@@ -181,6 +187,30 @@
PCRE2_ERROR_BADREPLACEMENT means invalid use of $
*/
+/* This macro checks for space in the buffer before copying into it. On
+overflow, either give an error immediately, or keep on, accumulating the
+length. */
+
+#define CHECKMEMCPY(from,length) \
+ if (!overflowed && lengthleft < length) \
+ { \
+ if ((suboptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) == 0) goto NOROOM; \
+ overflowed = TRUE; \
+ extra_needed = length - lengthleft; \
+ } \
+ else if (overflowed) \
+ { \
+ extra_needed += length; \
+ } \
+ else \
+ { \
+ memcpy(buffer + buff_offset, from, CU2BYTES(length)); \
+ buff_offset += length; \
+ lengthleft -= length; \
+ }
+
+/* Here's the function */
+
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
@@ -193,20 +223,22 @@
int forcecasereset = 0;
uint32_t ovector_count;
uint32_t goptions = 0;
+uint32_t suboptions;
BOOL match_data_created = FALSE;
-BOOL global = FALSE;
-BOOL extended = FALSE;
BOOL literal = FALSE;
-BOOL uempty = FALSE; /* Unset/unknown groups => empty string */
+BOOL overflowed = FALSE;
#ifdef SUPPORT_UNICODE
BOOL utf = (code->overall_options & PCRE2_UTF) != 0;
#endif
+PCRE2_UCHAR temp[6];
PCRE2_SPTR ptr;
PCRE2_SPTR repend;
+PCRE2_SIZE extra_needed = 0;
PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength;
PCRE2_SIZE *ovector;
-buff_length = *blength;
+buff_offset = 0;
+lengthleft = buff_length = *blength;
*blength = PCRE2_UNSET;
/* Partial matching is not valid. */
@@ -248,33 +280,14 @@
}
#endif /* SUPPORT_UNICODE */
-/* Notice the global and extended options and remove them from the options that
-are passed to pcre2_match(). */
+/* Save the substitute options and remove them from the match options. */
-if ((options & PCRE2_SUBSTITUTE_GLOBAL) != 0)
- {
- options &= ~PCRE2_SUBSTITUTE_GLOBAL;
- global = TRUE;
- }
+suboptions = options & SUBSTITUTE_OPTIONS;
+options &= ~SUBSTITUTE_OPTIONS;
-if ((options & PCRE2_SUBSTITUTE_EXTENDED) != 0)
- {
- options &= ~PCRE2_SUBSTITUTE_EXTENDED;
- extended = TRUE;
- }
-
-if ((options & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0)
- {
- options &= ~PCRE2_SUBSTITUTE_UNSET_EMPTY;
- uempty = TRUE;
- }
-
/* Copy up to the start offset */
-if (start_offset > buff_length) goto NOROOM;
-memcpy(buffer, subject, start_offset * (PCRE2_CODE_UNIT_WIDTH/8));
-buff_offset = start_offset;
-lengthleft = buff_length - start_offset;
+CHECKMEMCPY(subject, start_offset);
/* Loop for global substituting. */
@@ -330,13 +343,11 @@
#endif
}
+ /* Copy what we have advanced past, reset the special global options, and
+ continue to the next match. */
+
fraglength = start_offset - save_start;
- if (lengthleft < fraglength) goto NOROOM;
- memcpy(buffer + buff_offset, subject + save_start,
- fraglength*(PCRE2_CODE_UNIT_WIDTH/8));
- buff_offset += fraglength;
- lengthleft -= fraglength;
-
+ CHECKMEMCPY(subject + save_start, fraglength);
goptions = 0;
continue;
}
@@ -350,8 +361,8 @@
goto EXIT;
}
- /* Paranoid check for integer overflow; surely no real call to this function
- would ever hit this! */
+ /* Count substitutions with a paranoid check for integer overflow; surely no
+ real call to this function would ever hit this! */
if (subs == INT_MAX)
{
@@ -358,17 +369,13 @@
rc = PCRE2_ERROR_TOOMANYREPLACE;
goto EXIT;
}
+ subs++;
- /* Count substitutions and proceed */
+ /* Copy the text leading up to the match. */
- subs++;
if (rc == 0) rc = ovector_count;
fraglength = ovector[0] - start_offset;
- if (fraglength >= lengthleft) goto NOROOM;
- memcpy(buffer + buff_offset, subject + start_offset,
- fraglength*(PCRE2_CODE_UNIT_WIDTH/8));
- buff_offset += fraglength;
- lengthleft -= fraglength;
+ CHECKMEMCPY(subject + start_offset, fraglength);
/* Process the replacement string. Literal mode is set by \Q, but only in
extended mode when backslashes are being interpreted. In extended mode we
@@ -378,12 +385,13 @@
for (;;)
{
uint32_t ch;
+ unsigned int chlen;
/* If at the end of a nested substring, pop the stack. */
if (ptr >= repend)
{
- if (ptrstackptr <= 0) break;
+ if (ptrstackptr <= 0) break; /* End of replacement string */
repend = ptrstack[--ptrstackptr];
ptr = ptrstack[--ptrstackptr];
continue;
@@ -450,12 +458,22 @@
group = group * 10 + next - CHAR_0;
/* A check for a number greater than the hightest captured group
- is sufficient here; no need for a separate overflow check. */
+ is sufficient here; no need for a separate overflow check. If unknown
+ groups are to be treated as unset, just skip over any remaining
+ digits and carry on. */
if (group > code->top_bracket)
{
- rc = PCRE2_ERROR_NOSUBSTRING;
- goto PTREXIT;
+ if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ while (++ptr < repend && *ptr >= CHAR_0 && *ptr <= CHAR_9);
+ break;
+ }
+ else
+ {
+ rc = PCRE2_ERROR_NOSUBSTRING;
+ goto PTREXIT;
+ }
}
}
}
@@ -478,7 +496,8 @@
if (inparens)
{
- if (extended && !star && ptr < repend - 2 && next == CHAR_COLON)
+ if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ !star && ptr < repend - 2 && next == CHAR_COLON)
{
special = *(++ptr);
if (special != CHAR_PLUS && special != CHAR_MINUS)
@@ -513,8 +532,8 @@
ptr++;
}
- /* Have found a syntactically correct group number or name, or
- *name. Only *MARK is currently recognized. */
+ /* Have found a syntactically correct group number or name, or *name.
+ Only *MARK is currently recognized. */
if (star)
{
@@ -523,11 +542,10 @@
PCRE2_SPTR mark = pcre2_get_mark(match_data);
if (mark != NULL)
{
- while (*mark != 0)
- {
- if (lengthleft-- < 1) goto NOROOM;
- buffer[buff_offset++] = *mark++;
- }
+ PCRE2_SPTR mark_start = mark;
+ while (*mark != 0) mark++;
+ fraglength = mark - mark_start;
+ CHECKMEMCPY(mark_start, fraglength);
}
}
else goto BAD;
@@ -541,31 +559,41 @@
PCRE2_SPTR subptr, subptrend;
/* Find a number for a named group. In case there are duplicate names,
- search for the first one that is set. */
+ search for the first one that is set. If the name is not found when
+ PCRE2_SUBSTITUTE_UNKNOWN_EMPTY is set, set the group number to a
+ non-existent group. */
if (group < 0)
{
PCRE2_SPTR first, last, entry;
rc = pcre2_substring_nametable_scan(code, name, &first, &last);
- if (rc < 0) goto PTREXIT;
- for (entry = first; entry <= last; entry += rc)
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
{
- uint32_t ng = GET2(entry, 0);
- if (ng < ovector_count)
+ group = code->top_bracket + 1;
+ }
+ else
+ {
+ if (rc < 0) goto PTREXIT;
+ for (entry = first; entry <= last; entry += rc)
{
- if (group < 0) group = ng; /* First in ovector */
- if (ovector[ng*2] != PCRE2_UNSET)
+ uint32_t ng = GET2(entry, 0);
+ if (ng < ovector_count)
{
- group = ng; /* First that is set */
- break;
+ if (group < 0) group = ng; /* First in ovector */
+ if (ovector[ng*2] != PCRE2_UNSET)
+ {
+ group = ng; /* First that is set */
+ break;
+ }
}
}
- }
- /* If group is still negative, it means we did not find a group that
- is in the ovector. Just set the first group. */
+ /* If group is still negative, it means we did not find a group
+ that is in the ovector. Just set the first group. */
- if (group < 0) group = GET2(first, 0);
+ if (group < 0) group = GET2(first, 0);
+ }
}
/* We now have a group that is identified by number. Find the length of
@@ -575,10 +603,15 @@
rc = pcre2_substring_length_bynumber(match_data, group, &sublength);
if (rc < 0)
{
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ rc = PCRE2_ERROR_UNSET;
+ }
if (rc != PCRE2_ERROR_UNSET) goto PTREXIT; /* Non-unset errors */
if (special == 0) /* Plain substitution */
{
- if (uempty) continue; /* Treat as empty */
+ if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue;
goto PTREXIT; /* Else error */
}
}
@@ -646,26 +679,13 @@
}
#ifdef SUPPORT_UNICODE
- if (utf)
- {
- unsigned int chlen;
-#if PCRE2_CODE_UNIT_WIDTH == 8
- if (lengthleft < 6) goto NOROOM;
-#elif PCRE2_CODE_UNIT_WIDTH == 16
- if (lengthleft < 2) goto NOROOM;
-#else
- if (lengthleft < 1) goto NOROOM;
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
#endif
- chlen = PRIV(ord2utf)(ch, buffer + buff_offset);
- buff_offset += chlen;
- lengthleft -= chlen;
- }
- else
-#endif
{
- if (lengthleft-- < 1) goto NOROOM;
- buffer[buff_offset++] = ch;
+ temp[0] = ch;
+ chlen = 1;
}
+ CHECKMEMCPY(temp, chlen);
}
}
}
@@ -675,7 +695,8 @@
the case-forcing escapes are not supported in pcre2_compile() so must be
recognized here. */
- else if (extended && *ptr == CHAR_BACKSLASH)
+ else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ *ptr == CHAR_BACKSLASH)
{
int errorcode = 0;
@@ -756,33 +777,19 @@
)[ch/8] & (1 << (ch%8))) == 0)
ch = (code->tables + fcc_offset)[ch];
}
-
forcecase = forcecasereset;
}
#ifdef SUPPORT_UNICODE
- if (utf)
- {
- unsigned int chlen;
-#if PCRE2_CODE_UNIT_WIDTH == 8
- if (lengthleft < 6) goto NOROOM;
-#elif PCRE2_CODE_UNIT_WIDTH == 16
- if (lengthleft < 2) goto NOROOM;
-#else
- if (lengthleft < 1) goto NOROOM;
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
#endif
- chlen = PRIV(ord2utf)(ch, buffer + buff_offset);
- buff_offset += chlen;
- lengthleft -= chlen;
- }
- else
-#endif
{
- if (lengthleft-- < 1) goto NOROOM;
- buffer[buff_offset++] = ch;
+ temp[0] = ch;
+ chlen = 1;
}
- }
- }
+ CHECKMEMCPY(temp, chlen);
+ } /* End handling a literal code unit */
+ } /* End of loop for scanning the replacement. */
/* The replacement has been copied to the output. Update the start offset to
point to the rest of the subject string. If we matched an empty string,
@@ -791,19 +798,34 @@
start_offset = ovector[1];
goptions = (ovector[0] != ovector[1])? 0 :
PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART;
- } while (global); /* Repeat "do" loop */
+ } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0); /* Repeat "do" loop */
-/* Copy the rest of the subject and return the number of substitutions. */
+/* Copy the rest of the subject. */
-rc = subs;
fraglength = length - start_offset;
-if (fraglength + 1 > lengthleft) goto NOROOM;
-memcpy(buffer + buff_offset, subject + start_offset,
- fraglength*(PCRE2_CODE_UNIT_WIDTH/8));
-buff_offset += fraglength;
-buffer[buff_offset] = 0;
-*blength = buff_offset;
+CHECKMEMCPY(subject + start_offset, fraglength);
+temp[0] = 0;
+CHECKMEMCPY(temp , 1);
+/* If overflowed is set it means the PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set,
+and matching has carried on after a full buffer, in order to compute the length
+needed. Otherwise, an overflow generates an immediate error return. */
+
+if (overflowed)
+ {
+ rc = PCRE2_ERROR_NOMEMORY;
+ *blength = buff_length + extra_needed;
+ }
+
+/* After a successful execution, return the number of substitutions and set the
+length of buffer used, excluding the trailing zero. */
+
+else
+ {
+ rc = subs;
+ *blength = buff_offset - 1;
+ }
+
EXIT:
if (match_data_created) pcre2_match_data_free(match_data);
else match_data->rc = rc;
Modified: code/trunk/src/pcre2test.c
===================================================================
--- code/trunk/src/pcre2test.c 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/src/pcre2test.c 2015-12-12 18:45:40 UTC (rev 465)
@@ -399,40 +399,51 @@
MOD_STR }; /* Is a string */
/* Control bits. Some apply to compiling, some to matching, but some can be set
-either on a pattern or a data line, so they must all be distinct. */
+either on a pattern or a data line, so they must all be distinct. There are now
+so many of them that they are split into two fields. */
-#define CTL_AFTERTEXT 0x00000001u
-#define CTL_ALLAFTERTEXT 0x00000002u
-#define CTL_ALLCAPTURES 0x00000004u
-#define CTL_ALLUSEDTEXT 0x00000008u
-#define CTL_ALTGLOBAL 0x00000010u
-#define CTL_BINCODE 0x00000020u
-#define CTL_CALLOUT_CAPTURE 0x00000040u
-#define CTL_CALLOUT_INFO 0x00000080u
-#define CTL_CALLOUT_NONE 0x00000100u
-#define CTL_DFA 0x00000200u
-#define CTL_EXPAND 0x00000400u
-#define CTL_FINDLIMITS 0x00000800u
-#define CTL_FULLBINCODE 0x00001000u
-#define CTL_GETALL 0x00002000u
-#define CTL_GLOBAL 0x00004000u
-#define CTL_HEXPAT 0x00008000u
-#define CTL_INFO 0x00010000u
-#define CTL_JITFAST 0x00020000u
-#define CTL_JITVERIFY 0x00040000u
-#define CTL_MARK 0x00080000u
-#define CTL_MEMORY 0x00100000u
-#define CTL_NULLCONTEXT 0x00200000u
-#define CTL_POSIX 0x00400000u
-#define CTL_PUSH 0x00800000u
-#define CTL_STARTCHAR 0x01000000u
-#define CTL_SUBSTITUTE_EXTENDED 0x02000000u
-#define CTL_SUBSTITUTE_UNSET_EMPTY 0x04000000u
-#define CTL_ZERO_TERMINATE 0x08000000u
+#define CTL_AFTERTEXT 0x00000001u
+#define CTL_ALLAFTERTEXT 0x00000002u
+#define CTL_ALLCAPTURES 0x00000004u
+#define CTL_ALLUSEDTEXT 0x00000008u
+#define CTL_ALTGLOBAL 0x00000010u
+#define CTL_BINCODE 0x00000020u
+#define CTL_CALLOUT_CAPTURE 0x00000040u
+#define CTL_CALLOUT_INFO 0x00000080u
+#define CTL_CALLOUT_NONE 0x00000100u
+#define CTL_DFA 0x00000200u
+#define CTL_EXPAND 0x00000400u
+#define CTL_FINDLIMITS 0x00000800u
+#define CTL_FULLBINCODE 0x00001000u
+#define CTL_GETALL 0x00002000u
+#define CTL_GLOBAL 0x00004000u
+#define CTL_HEXPAT 0x00008000u
+#define CTL_INFO 0x00010000u
+#define CTL_JITFAST 0x00020000u
+#define CTL_JITVERIFY 0x00040000u
+#define CTL_MARK 0x00080000u
+#define CTL_MEMORY 0x00100000u
+#define CTL_NULLCONTEXT 0x00200000u
+#define CTL_POSIX 0x00400000u
+#define CTL_PUSH 0x00800000u
+#define CTL_STARTCHAR 0x01000000u
+#define CTL_ZERO_TERMINATE 0x02000000u
+/* Spare 0x04000000u */
+/* Spare 0x08000000u */
+/* Spare 0x10000000u */
+/* Spare 0x20000000u */
+#define CTL_NL_SET 0x40000000u /* Informational */
+#define CTL_BSR_SET 0x80000000u /* Informational */
-#define CTL_BSR_SET 0x80000000u /* This is informational */
-#define CTL_NL_SET 0x40000000u /* This is informational */
+/* Second control word */
+#define CTL2_SUBSTITUTE_EXTENDED 0x00000001u
+#define CTL2_SUBSTITUTE_OVERFLOW_LENGTH 0x00000002u
+#define CTL2_SUBSTITUTE_UNKNOWN_UNSET 0x00000004u
+#define CTL2_SUBSTITUTE_UNSET_EMPTY 0x00000008u
+
+/* Combinations */
+
#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */
#define CTL_ANYINFO (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO)
#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL)
@@ -448,10 +459,13 @@
CTL_GLOBAL|\
CTL_MARK|\
CTL_MEMORY|\
- CTL_STARTCHAR|\
- CTL_SUBSTITUTE_EXTENDED|\
- CTL_SUBSTITUTE_UNSET_EMPTY)
+ CTL_STARTCHAR)
+#define CTL2_ALLPD (CTL2_SUBSTITUTE_EXTENDED|\
+ CTL2_SUBSTITUTE_OVERFLOW_LENGTH|\
+ CTL2_SUBSTITUTE_UNKNOWN_UNSET|\
+ CTL2_SUBSTITUTE_UNSET_EMPTY)
+
/* Structures for holding modifier information for patterns and subject strings
(data). Fields containing modifiers that can be set either for a pattern or a
subject must be at the start and in the same order in both cases so that the
@@ -460,6 +474,7 @@
typedef struct patctl { /* Structure for pattern modifiers. */
uint32_t options; /* Must be in same position as datctl */
uint32_t control; /* Must be in same position as datctl */
+ uint32_t control2; /* Must be in same position as datctl */
uint8_t replacement[REPLACE_MODSIZE]; /* So must this */
uint32_t jit;
uint32_t stackguard_test;
@@ -474,6 +489,7 @@
typedef struct datctl { /* Structure for data line modifiers. */
uint32_t options; /* Must be in same position as patctl */
uint32_t control; /* Must be in same position as patctl */
+ uint32_t control2; /* Must be in same position as patctl */
uint8_t replacement[REPLACE_MODSIZE]; /* So must this */
uint32_t cfail[2];
int32_t callout_data;
@@ -514,92 +530,94 @@
} modstruct;
static modstruct modlist[] = {
- { "aftertext", MOD_PNDP, MOD_CTL, CTL_AFTERTEXT, PO(control) },
- { "allaftertext", MOD_PNDP, MOD_CTL, CTL_ALLAFTERTEXT, PO(control) },
- { "allcaptures", MOD_PND, MOD_CTL, CTL_ALLCAPTURES, PO(control) },
- { "allow_empty_class", MOD_PAT, MOD_OPT, PCRE2_ALLOW_EMPTY_CLASS, PO(options) },
- { "allusedtext", MOD_PNDP, MOD_CTL, CTL_ALLUSEDTEXT, PO(control) },
- { "alt_bsux", MOD_PAT, MOD_OPT, PCRE2_ALT_BSUX, PO(options) },
- { "alt_circumflex", MOD_PAT, MOD_OPT, PCRE2_ALT_CIRCUMFLEX, PO(options) },
- { "alt_verbnames", MOD_PAT, MOD_OPT, PCRE2_ALT_VERBNAMES, PO(options) },
- { "altglobal", MOD_PND, MOD_CTL, CTL_ALTGLOBAL, PO(control) },
- { "anchored", MOD_PD, MOD_OPT, PCRE2_ANCHORED, PD(options) },
- { "auto_callout", MOD_PAT, MOD_OPT, PCRE2_AUTO_CALLOUT, PO(options) },
- { "bincode", MOD_PAT, MOD_CTL, CTL_BINCODE, PO(control) },
- { "bsr", MOD_CTC, MOD_BSR, 0, CO(bsr_convention) },
- { "callout_capture", MOD_DAT, MOD_CTL, CTL_CALLOUT_CAPTURE, DO(control) },
- { "callout_data", MOD_DAT, MOD_INS, 0, DO(callout_data) },
- { "callout_fail", MOD_DAT, MOD_IN2, 0, DO(cfail) },
- { "callout_info", MOD_PAT, MOD_CTL, CTL_CALLOUT_INFO, PO(control) },
- { "callout_none", MOD_DAT, MOD_CTL, CTL_CALLOUT_NONE, DO(control) },
- { "caseless", MOD_PATP, MOD_OPT, PCRE2_CASELESS, PO(options) },
- { "copy", MOD_DAT, MOD_NN, DO(copy_numbers), DO(copy_names) },
- { "debug", MOD_PAT, MOD_CTL, CTL_DEBUG, PO(control) },
- { "dfa", MOD_DAT, MOD_CTL, CTL_DFA, DO(control) },
- { "dfa_restart", MOD_DAT, MOD_OPT, PCRE2_DFA_RESTART, DO(options) },
- { "dfa_shortest", MOD_DAT, MOD_OPT, PCRE2_DFA_SHORTEST, DO(options) },
- { "dollar_endonly", MOD_PAT, MOD_OPT, PCRE2_DOLLAR_ENDONLY, PO(options) },
- { "dotall", MOD_PATP, MOD_OPT, PCRE2_DOTALL, PO(options) },
- { "dupnames", MOD_PATP, MOD_OPT, PCRE2_DUPNAMES, PO(options) },
- { "expand", MOD_PAT, MOD_CTL, CTL_EXPAND, PO(control) },
- { "extended", MOD_PATP, MOD_OPT, PCRE2_EXTENDED, PO(options) },
- { "find_limits", MOD_DAT, MOD_CTL, CTL_FINDLIMITS, DO(control) },
- { "firstline", MOD_PAT, MOD_OPT, PCRE2_FIRSTLINE, PO(options) },
- { "fullbincode", MOD_PAT, MOD_CTL, CTL_FULLBINCODE, PO(control) },
- { "get", MOD_DAT, MOD_NN, DO(get_numbers), DO(get_names) },
- { "getall", MOD_DAT, MOD_CTL, CTL_GETALL, DO(control) },
- { "global", MOD_PNDP, MOD_CTL, CTL_GLOBAL, PO(control) },
- { "hex", MOD_PAT, MOD_CTL, CTL_HEXPAT, PO(control) },
- { "info", MOD_PAT, MOD_CTL, CTL_INFO, PO(control) },
- { "jit", MOD_PAT, MOD_IND, 7, PO(jit) },
- { "jitfast", MOD_PAT, MOD_CTL, CTL_JITFAST, PO(control) },
- { "jitstack", MOD_DAT, MOD_INT, 0, DO(jitstack) },
- { "jitverify", MOD_PAT, MOD_CTL, CTL_JITVERIFY, PO(control) },
- { "locale", MOD_PAT, MOD_STR, LOCALESIZE, PO(locale) },
- { "mark", MOD_PNDP, MOD_CTL, CTL_MARK, PO(control) },
- { "match_limit", MOD_CTM, MOD_INT, 0, MO(match_limit) },
- { "match_unset_backref", MOD_PAT, MOD_OPT, PCRE2_MATCH_UNSET_BACKREF, PO(options) },
- { "max_pattern_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_length) },
- { "memory", MOD_PD, MOD_CTL, CTL_MEMORY, PD(control) },
- { "multiline", MOD_PATP, MOD_OPT, PCRE2_MULTILINE, PO(options) },
- { "never_backslash_c", MOD_PAT, MOD_OPT, PCRE2_NEVER_BACKSLASH_C, PO(options) },
- { "never_ucp", MOD_PAT, MOD_OPT, PCRE2_NEVER_UCP, PO(options) },
- { "never_utf", MOD_PAT, MOD_OPT, PCRE2_NEVER_UTF, PO(options) },
- { "newline", MOD_CTC, MOD_NL, 0, CO(newline_convention) },
- { "no_auto_capture", MOD_PAT, MOD_OPT, PCRE2_NO_AUTO_CAPTURE, PO(options) },
- { "no_auto_possess", MOD_PATP, MOD_OPT, PCRE2_NO_AUTO_POSSESS, PO(options) },
- { "no_dotstar_anchor", MOD_PAT, MOD_OPT, PCRE2_NO_DOTSTAR_ANCHOR, PO(options) },
- { "no_start_optimize", MOD_PATP, MOD_OPT, PCRE2_NO_START_OPTIMIZE, PO(options) },
- { "no_utf_check", MOD_PD, MOD_OPT, PCRE2_NO_UTF_CHECK, PD(options) },
- { "notbol", MOD_DAT, MOD_OPT, PCRE2_NOTBOL, DO(options) },
- { "notempty", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY, DO(options) },
- { "notempty_atstart", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY_ATSTART, DO(options) },
- { "noteol", MOD_DAT, MOD_OPT, PCRE2_NOTEOL, DO(options) },
- { "null_context", MOD_PD, MOD_CTL, CTL_NULLCONTEXT, PO(control) },
- { "offset", MOD_DAT, MOD_INT, 0, DO(offset) },
- { "offset_limit", MOD_CTM, MOD_SIZ, 0, MO(offset_limit)},
- { "ovector", MOD_DAT, MOD_INT, 0, DO(oveccount) },
- { "parens_nest_limit", MOD_CTC, MOD_INT, 0, CO(parens_nest_limit) },
- { "partial_hard", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
- { "partial_soft", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
- { "ph", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
- { "posix", MOD_PAT, MOD_CTL, CTL_POSIX, PO(control) },
- { "ps", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
- { "push", MOD_PAT, MOD_CTL, CTL_PUSH, PO(control) },
- { "recursion_limit", MOD_CTM, MOD_INT, 0, MO(recursion_limit) },
- { "regerror_buffsize", MOD_PAT, MOD_INT, 0, PO(regerror_buffsize) },
- { "replace", MOD_PND, MOD_STR, REPLACE_MODSIZE, PO(replacement) },
- { "stackguard", MOD_PAT, MOD_INT, 0, PO(stackguard_test) },
- { "startchar", MOD_PND, MOD_CTL, CTL_STARTCHAR, PO(control) },
- { "startoffset", MOD_DAT, MOD_INT, 0, DO(offset) },
- { "substitute_extended", MOD_PND, MOD_CTL, CTL_SUBSTITUTE_EXTENDED, PO(control) },
- { "substitute_unset_empty", MOD_PND, MOD_CTL, CTL_SUBSTITUTE_UNSET_EMPTY, PO(control) },
- { "tables", MOD_PAT, MOD_INT, 0, PO(tables_id) },
- { "ucp", MOD_PATP, MOD_OPT, PCRE2_UCP, PO(options) },
- { "ungreedy", MOD_PAT, MOD_OPT, PCRE2_UNGREEDY, PO(options) },
- { "use_offset_limit", MOD_PAT, MOD_OPT, PCRE2_USE_OFFSET_LIMIT, PO(options) },
- { "utf", MOD_PATP, MOD_OPT, PCRE2_UTF, PO(options) },
- { "zero_terminate", MOD_DAT, MOD_CTL, CTL_ZERO_TERMINATE, DO(control) }
+ { "aftertext", MOD_PNDP, MOD_CTL, CTL_AFTERTEXT, PO(control) },
+ { "allaftertext", MOD_PNDP, MOD_CTL, CTL_ALLAFTERTEXT, PO(control) },
+ { "allcaptures", MOD_PND, MOD_CTL, CTL_ALLCAPTURES, PO(control) },
+ { "allow_empty_class", MOD_PAT, MOD_OPT, PCRE2_ALLOW_EMPTY_CLASS, PO(options) },
+ { "allusedtext", MOD_PNDP, MOD_CTL, CTL_ALLUSEDTEXT, PO(control) },
+ { "alt_bsux", MOD_PAT, MOD_OPT, PCRE2_ALT_BSUX, PO(options) },
+ { "alt_circumflex", MOD_PAT, MOD_OPT, PCRE2_ALT_CIRCUMFLEX, PO(options) },
+ { "alt_verbnames", MOD_PAT, MOD_OPT, PCRE2_ALT_VERBNAMES, PO(options) },
+ { "altglobal", MOD_PND, MOD_CTL, CTL_ALTGLOBAL, PO(control) },
+ { "anchored", MOD_PD, MOD_OPT, PCRE2_ANCHORED, PD(options) },
+ { "auto_callout", MOD_PAT, MOD_OPT, PCRE2_AUTO_CALLOUT, PO(options) },
+ { "bincode", MOD_PAT, MOD_CTL, CTL_BINCODE, PO(control) },
+ { "bsr", MOD_CTC, MOD_BSR, 0, CO(bsr_convention) },
+ { "callout_capture", MOD_DAT, MOD_CTL, CTL_CALLOUT_CAPTURE, DO(control) },
+ { "callout_data", MOD_DAT, MOD_INS, 0, DO(callout_data) },
+ { "callout_fail", MOD_DAT, MOD_IN2, 0, DO(cfail) },
+ { "callout_info", MOD_PAT, MOD_CTL, CTL_CALLOUT_INFO, PO(control) },
+ { "callout_none", MOD_DAT, MOD_CTL, CTL_CALLOUT_NONE, DO(control) },
+ { "caseless", MOD_PATP, MOD_OPT, PCRE2_CASELESS, PO(options) },
+ { "copy", MOD_DAT, MOD_NN, DO(copy_numbers), DO(copy_names) },
+ { "debug", MOD_PAT, MOD_CTL, CTL_DEBUG, PO(control) },
+ { "dfa", MOD_DAT, MOD_CTL, CTL_DFA, DO(control) },
+ { "dfa_restart", MOD_DAT, MOD_OPT, PCRE2_DFA_RESTART, DO(options) },
+ { "dfa_shortest", MOD_DAT, MOD_OPT, PCRE2_DFA_SHORTEST, DO(options) },
+ { "dollar_endonly", MOD_PAT, MOD_OPT, PCRE2_DOLLAR_ENDONLY, PO(options) },
+ { "dotall", MOD_PATP, MOD_OPT, PCRE2_DOTALL, PO(options) },
+ { "dupnames", MOD_PATP, MOD_OPT, PCRE2_DUPNAMES, PO(options) },
+ { "expand", MOD_PAT, MOD_CTL, CTL_EXPAND, PO(control) },
+ { "extended", MOD_PATP, MOD_OPT, PCRE2_EXTENDED, PO(options) },
+ { "find_limits", MOD_DAT, MOD_CTL, CTL_FINDLIMITS, DO(control) },
+ { "firstline", MOD_PAT, MOD_OPT, PCRE2_FIRSTLINE, PO(options) },
+ { "fullbincode", MOD_PAT, MOD_CTL, CTL_FULLBINCODE, PO(control) },
+ { "get", MOD_DAT, MOD_NN, DO(get_numbers), DO(get_names) },
+ { "getall", MOD_DAT, MOD_CTL, CTL_GETALL, DO(control) },
+ { "global", MOD_PNDP, MOD_CTL, CTL_GLOBAL, PO(control) },
+ { "hex", MOD_PAT, MOD_CTL, CTL_HEXPAT, PO(control) },
+ { "info", MOD_PAT, MOD_CTL, CTL_INFO, PO(control) },
+ { "jit", MOD_PAT, MOD_IND, 7, PO(jit) },
+ { "jitfast", MOD_PAT, MOD_CTL, CTL_JITFAST, PO(control) },
+ { "jitstack", MOD_DAT, MOD_INT, 0, DO(jitstack) },
+ { "jitverify", MOD_PAT, MOD_CTL, CTL_JITVERIFY, PO(control) },
+ { "locale", MOD_PAT, MOD_STR, LOCALESIZE, PO(locale) },
+ { "mark", MOD_PNDP, MOD_CTL, CTL_MARK, PO(control) },
+ { "match_limit", MOD_CTM, MOD_INT, 0, MO(match_limit) },
+ { "match_unset_backref", MOD_PAT, MOD_OPT, PCRE2_MATCH_UNSET_BACKREF, PO(options) },
+ { "max_pattern_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_length) },
+ { "memory", MOD_PD, MOD_CTL, CTL_MEMORY, PD(control) },
+ { "multiline", MOD_PATP, MOD_OPT, PCRE2_MULTILINE, PO(options) },
+ { "never_backslash_c", MOD_PAT, MOD_OPT, PCRE2_NEVER_BACKSLASH_C, PO(options) },
+ { "never_ucp", MOD_PAT, MOD_OPT, PCRE2_NEVER_UCP, PO(options) },
+ { "never_utf", MOD_PAT, MOD_OPT, PCRE2_NEVER_UTF, PO(options) },
+ { "newline", MOD_CTC, MOD_NL, 0, CO(newline_convention) },
+ { "no_auto_capture", MOD_PAT, MOD_OPT, PCRE2_NO_AUTO_CAPTURE, PO(options) },
+ { "no_auto_possess", MOD_PATP, MOD_OPT, PCRE2_NO_AUTO_POSSESS, PO(options) },
+ { "no_dotstar_anchor", MOD_PAT, MOD_OPT, PCRE2_NO_DOTSTAR_ANCHOR, PO(options) },
+ { "no_start_optimize", MOD_PATP, MOD_OPT, PCRE2_NO_START_OPTIMIZE, PO(options) },
+ { "no_utf_check", MOD_PD, MOD_OPT, PCRE2_NO_UTF_CHECK, PD(options) },
+ { "notbol", MOD_DAT, MOD_OPT, PCRE2_NOTBOL, DO(options) },
+ { "notempty", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY, DO(options) },
+ { "notempty_atstart", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY_ATSTART, DO(options) },
+ { "noteol", MOD_DAT, MOD_OPT, PCRE2_NOTEOL, DO(options) },
+ { "null_context", MOD_PD, MOD_CTL, CTL_NULLCONTEXT, PO(control) },
+ { "offset", MOD_DAT, MOD_INT, 0, DO(offset) },
+ { "offset_limit", MOD_CTM, MOD_SIZ, 0, MO(offset_limit)},
+ { "ovector", MOD_DAT, MOD_INT, 0, DO(oveccount) },
+ { "parens_nest_limit", MOD_CTC, MOD_INT, 0, CO(parens_nest_limit) },
+ { "partial_hard", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
+ { "partial_soft", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
+ { "ph", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
+ { "posix", MOD_PAT, MOD_CTL, CTL_POSIX, PO(control) },
+ { "ps", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
+ { "push", MOD_PAT, MOD_CTL, CTL_PUSH, PO(control) },
+ { "recursion_limit", MOD_CTM, MOD_INT, 0, MO(recursion_limit) },
+ { "regerror_buffsize", MOD_PAT, MOD_INT, 0, PO(regerror_buffsize) },
+ { "replace", MOD_PND, MOD_STR, REPLACE_MODSIZE, PO(replacement) },
+ { "stackguard", MOD_PAT, MOD_INT, 0, PO(stackguard_test) },
+ { "startchar", MOD_PND, MOD_CTL, CTL_STARTCHAR, PO(control) },
+ { "startoffset", MOD_DAT, MOD_INT, 0, DO(offset) },
+ { "substitute_extended", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_EXTENDED, PO(control2) },
+ { "substitute_overflow_length", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_OVERFLOW_LENGTH, PO(control2) },
+ { "substitute_unknown_unset", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNKNOWN_UNSET, PO(control2) },
+ { "substitute_unset_empty", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNSET_EMPTY, PO(control2) },
+ { "tables", MOD_PAT, MOD_INT, 0, PO(tables_id) },
+ { "ucp", MOD_PATP, MOD_OPT, PCRE2_UCP, PO(options) },
+ { "ungreedy", MOD_PAT, MOD_OPT, PCRE2_UNGREEDY, PO(options) },
+ { "use_offset_limit", MOD_PAT, MOD_OPT, PCRE2_USE_OFFSET_LIMIT, PO(options) },
+ { "utf", MOD_PATP, MOD_OPT, PCRE2_UTF, PO(options) },
+ { "zero_terminate", MOD_DAT, MOD_CTL, CTL_ZERO_TERMINATE, DO(control) }
};
#define MODLISTCOUNT sizeof(modlist)/sizeof(modstruct)
@@ -613,10 +631,13 @@
#define POSIX_SUPPORTED_COMPILE_CONTROLS ( \
CTL_AFTERTEXT|CTL_ALLAFTERTEXT|CTL_EXPAND|CTL_POSIX)
+#define POSIX_SUPPORTED_COMPILE_CONTROLS2 (0)
+
#define POSIX_SUPPORTED_MATCH_OPTIONS ( \
PCRE2_NOTBOL|PCRE2_NOTEMPTY|PCRE2_NOTEOL)
-#define POSIX_SUPPORTED_MATCH_CONTROLS (CTL_AFTERTEXT|CTL_ALLAFTERTEXT)
+#define POSIX_SUPPORTED_MATCH_CONTROLS (CTL_AFTERTEXT|CTL_ALLAFTERTEXT)
+#define POSIX_SUPPORTED_MATCH_CONTROLS2 (0)
/* Control bits that are not ignored with 'push'. */
@@ -624,15 +645,19 @@
CTL_BINCODE|CTL_CALLOUT_INFO|CTL_FULLBINCODE|CTL_HEXPAT|CTL_INFO| \
CTL_JITVERIFY|CTL_MEMORY|CTL_PUSH|CTL_BSR_SET|CTL_NL_SET)
+#define PUSH_SUPPORTED_COMPILE_CONTROLS2 (0)
+
/* Controls that apply only at compile time with 'push'. */
-#define PUSH_COMPILE_ONLY_CONTROLS CTL_JITVERIFY
+#define PUSH_COMPILE_ONLY_CONTROLS CTL_JITVERIFY
+#define PUSH_COMPILE_ONLY_CONTROLS2 (0)
/* Controls that are forbidden with #pop. */
#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_PUSH)
-/* Pattern controls that are mutually exclusive. */
+/* Pattern controls that are mutually exclusive. At present these are all in
+the first control word. */
static uint32_t exclusive_pat_controls[] = {
CTL_POSIX | CTL_HEXPAT,
@@ -639,8 +664,8 @@
CTL_POSIX | CTL_PUSH,
CTL_EXPAND | CTL_HEXPAT };
-/* Data controls that are mutually exclusive. */
-
+/* Data controls that are mutually exclusive. At present these are all in the
+first control word. */
static uint32_t exclusive_dat_controls[] = {
CTL_ALLUSEDTEXT | CTL_STARTCHAR,
CTL_FINDLIMITS | CTL_NULLCONTEXT };
@@ -3528,6 +3553,7 @@
Arguments:
controls control bits
+ controls2 more control bits
before text to print before
Returns: nothing
@@ -3534,9 +3560,9 @@
*/
static void
-show_controls(uint32_t controls, const char *before)
+show_controls(uint32_t controls, uint32_t controls2, const char *before)
{
-fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
before,
((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "",
((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "",
@@ -3565,8 +3591,10 @@
((controls & CTL_POSIX) != 0)? " posix" : "",
((controls & CTL_PUSH) != 0)? " push" : "",
((controls & CTL_STARTCHAR) != 0)? " startchar" : "",
- ((controls & CTL_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "",
- ((controls & CTL_SUBSTITUTE_UNSET_EMPTY) != 0)? " substitute_unset_empty" : "",
+ ((controls2 & CTL2_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "",
+ ((controls2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)? " substitute_overflow_length" : "",
+ ((controls2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) != 0)? " substitute_unknown_unset" : "",
+ ((controls2 & CTL2_SUBSTITUTE_UNSET_EMPTY) != 0)? " substitute_unset_empty" : "",
((controls & CTL_ZERO_TERMINATE) != 0)? " zero_terminate" : "");
}
@@ -4398,7 +4426,8 @@
if (!decode_modifiers(p, CTX_PAT, &pat_patctl, NULL)) return PR_SKIP;
utf = (pat_patctl.options & PCRE2_UTF) != 0;
-/* Check for mutually exclusive modifiers. */
+/* Check for mutually exclusive modifiers. At present, these are all in the
+first control word. */
for (k = 0; k < sizeof(exclusive_pat_controls)/sizeof(uint32_t); k++)
{
@@ -4405,7 +4434,7 @@
uint32_t c = pat_patctl.control & exclusive_pat_controls[k];
if (c != 0 && c != (c & (~c+1)))
{
- show_controls(c, "** Not allowed together:");
+ show_controls(c, 0, "** Not allowed together:");
fprintf(outfile, "\n");
return PR_SKIP;
}
@@ -4605,9 +4634,11 @@
pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS, msg, "");
msg = "";
}
- if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0)
+ if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+ (pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2) != 0)
{
- show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS, msg);
+ show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS,
+ pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2, msg);
msg = "";
}
@@ -4663,15 +4694,19 @@
fprintf(outfile, "** Replacement text is not supported with 'push'.\n");
return PR_OK;
}
- if ((pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS) != 0)
+ if ((pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+ (pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2) != 0)
{
show_controls(pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS,
+ pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2,
"** Ignored when compiled pattern is stacked with 'push':");
fprintf(outfile, "\n");
}
- if ((pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS) != 0)
+ if ((pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS) != 0 ||
+ (pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2) != 0)
{
show_controls(pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS,
+ pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2,
"** Applies only to compile when pattern is stacked with 'push':");
fprintf(outfile, "\n");
}
@@ -5340,6 +5375,7 @@
DATCTXCPY(dat_context, default_dat_context);
memcpy(&dat_datctl, &def_datctl, sizeof(datctl));
dat_datctl.control |= (pat_patctl.control & CTL_ALLPD);
+dat_datctl.control2 |= (pat_patctl.control2 & CTL2_ALLPD);
strcpy((char *)dat_datctl.replacement, (char *)pat_patctl.replacement);
/* Initialize for scanning the data line. */
@@ -5657,7 +5693,8 @@
if (p[-1] != 0 && !decode_modifiers(p, CTX_DAT, NULL, &dat_datctl))
return PR_OK;
-/* Check for mutually exclusive modifiers. */
+/* Check for mutually exclusive modifiers. At present, these are all in the
+first control word. */
for (k = 0; k < sizeof(exclusive_dat_controls)/sizeof(uint32_t); k++)
{
@@ -5664,7 +5701,7 @@
c = dat_datctl.control & exclusive_dat_controls[k];
if (c != 0 && c != (c & (~c+1)))
{
- show_controls(c, "** Not allowed together:");
+ show_controls(c, 0, "** Not allowed together:");
fprintf(outfile, "\n");
return PR_OK;
}
@@ -5717,9 +5754,11 @@
show_match_options(dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS);
msg = "";
}
- if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0)
+ if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0 ||
+ (dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2) != 0)
{
- show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS, msg);
+ show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS,
+ dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2, msg);
msg = "";
}
@@ -5891,9 +5930,13 @@
xoptions = (((dat_datctl.control & CTL_GLOBAL) == 0)? 0 :
PCRE2_SUBSTITUTE_GLOBAL) |
- (((dat_datctl.control & CTL_SUBSTITUTE_EXTENDED) == 0)? 0 :
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_EXTENDED) == 0)? 0 :
PCRE2_SUBSTITUTE_EXTENDED) |
- (((dat_datctl.control & CTL_SUBSTITUTE_UNSET_EMPTY) == 0)? 0 :
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) == 0)? 0 :
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) == 0)? 0 :
+ PCRE2_SUBSTITUTE_UNKNOWN_UNSET) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNSET_EMPTY) == 0)? 0 :
PCRE2_SUBSTITUTE_UNSET_EMPTY);
SETCASTPTR(r, rbuffer); /* Sets r8, r16, or r32, as appropriate. */
@@ -5987,12 +6030,16 @@
if (rc < 0)
{
+ PCRE2_SIZE msize;
fprintf(outfile, "Failed: error %d", rc);
- if (nsize != PCRE2_UNSET)
+ if (rc != PCRE2_ERROR_NOMEMORY && nsize != PCRE2_UNSET)
fprintf(outfile, " at offset %ld in replacement", nsize);
fprintf(outfile, ": ");
- PCRE2_GET_ERROR_MESSAGE(nsize, rc, pbuffer);
- PCHARSV(CASTVAR(void *, pbuffer), 0, nsize, FALSE, outfile);
+ PCRE2_GET_ERROR_MESSAGE(msize, rc, pbuffer);
+ PCHARSV(CASTVAR(void *, pbuffer), 0, msize, FALSE, outfile);
+ if (rc == PCRE2_ERROR_NOMEMORY &&
+ (xoptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)
+ fprintf(outfile, ": %ld code units are needed", nsize);
}
else
{
@@ -6850,7 +6897,8 @@
We cannot test this till runtime because "offsetof" does not work in the
preprocessor. */
-if (PO(options) != DO(options) || PO(control) != DO(control))
+if (PO(options) != DO(options) || PO(control) != DO(control) ||
+ PO(control2) != DO(control2))
{
fprintf(stderr, "** Coding error: "
"options and control offsets for pattern and data must be the same.\n");
Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/testdata/testinput2 2015-12-12 18:45:40 UTC (rev 465)
@@ -4042,8 +4042,6 @@
/(((((a)))))/parens_nest_limit=2
-# Tests for pcre2_substitute()
-
/abc/replace=XYZ
123123
123abc123
@@ -4149,12 +4147,25 @@
/(*:pear)apple|(*:orange)lemon|(*:strawberry)blackberry/g,replace=[22]${*MARK}
apple lemon blackberry
+ apple lemon blackberry\=substitute_overflow_length
/(*:pear)apple|(*:orange)lemon|(*:strawberry)blackberry/g,replace=[23]${*MARK}
apple lemon blackberry
-# End of substitute tests
+/abc/
+ 123abc123\=replace=[9]XYZ
+ 123abc123\=substitute_overflow_length,replace=[9]XYZ
+ 123abc123\=substitute_overflow_length,replace=[6]XYZ
+ 123abc123\=substitute_overflow_length,replace=[1]XYZ
+ 123abc123\=substitute_overflow_length,replace=[0]XYZ
+/a(b)c/
+ 123abc123\=replace=[9]x$1z
+ 123abc123\=substitute_overflow_length,replace=[9]x$1z
+ 123abc123\=substitute_overflow_length,replace=[6]x$1z
+ 123abc123\=substitute_overflow_length,replace=[1]x$1z
+ 123abc123\=substitute_overflow_length,replace=[0]x$1z
+
"((?=(?(?=(?(?=(?(?=()))))))))"
a
@@ -4749,12 +4760,24 @@
cat\=replace=>$1<,substitute_unset_empty
xbcom\=replace=>$1<,substitute_unset_empty
+/a|(b)c/substitute_extended
+ cat\=replace=>${2:-xx}<
+ cat\=replace=>${2:-xx}<,substitute_unknown_unset
+ cat\=replace=>${X:-xx}<,substitute_unknown_unset
+
/a|(?'X'b)c/replace=>$X<,substitute_unset_empty
cat
xbcom
+/a|(?'X'b)c/replace=>$Y<,substitute_unset_empty
+ cat
+ cat\=substitute_unknown_unset
+ cat\=substitute_unknown_unset,-substitute_unset_empty
+
/a|(b)c/replace=>$2<,substitute_unset_empty
cat
+ cat\=substitute_unknown_unset
+ cat\=substitute_unknown_unset,-substitute_unset_empty
/()()()/use_offset_limit
\=ovector=11000000000
Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2 2015-12-09 17:33:07 UTC (rev 464)
+++ code/trunk/testdata/testoutput2 2015-12-12 18:45:40 UTC (rev 465)
@@ -13432,8 +13432,6 @@
/(((((a)))))/parens_nest_limit=2
Failed: error 119 at offset 3: parentheses are too deeply nested
-# Tests for pcre2_substitute()
-
/abc/replace=XYZ
123123
0: 123123
@@ -13583,13 +13581,37 @@
/(*:pear)apple|(*:orange)lemon|(*:strawberry)blackberry/g,replace=[22]${*MARK}
apple lemon blackberry
Failed: error -48: no more memory
+ apple lemon blackberry\=substitute_overflow_length
+Failed: error -48: no more memory: 23 code units are needed
/(*:pear)apple|(*:orange)lemon|(*:strawberry)blackberry/g,replace=[23]${*MARK}
apple lemon blackberry
3: pear orange strawberry
-# End of substitute tests
+/abc/
+ 123abc123\=replace=[9]XYZ
+Failed: error -48: no more memory
+ 123abc123\=substitute_overflow_length,replace=[9]XYZ
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[6]XYZ
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[1]XYZ
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[0]XYZ
+Failed: error -48: no more memory: 10 code units are needed
+/a(b)c/
+ 123abc123\=replace=[9]x$1z
+Failed: error -48: no more memory
+ 123abc123\=substitute_overflow_length,replace=[9]x$1z
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[6]x$1z
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[1]x$1z
+Failed: error -48: no more memory: 10 code units are needed
+ 123abc123\=substitute_overflow_length,replace=[0]x$1z
+Failed: error -48: no more memory: 10 code units are needed
+
"((?=(?(?=(?(?=(?(?=()))))))))"
a
0:
@@ -15075,6 +15097,14 @@
xbcom\=replace=>$1<,substitute_unset_empty
1: x>b<om
+/a|(b)c/substitute_extended
+ cat\=replace=>${2:-xx}<
+Failed: error -49 at offset 9 in replacement: unknown substring
+ cat\=replace=>${2:-xx}<,substitute_unknown_unset
+ 1: c>xx<t
+ cat\=replace=>${X:-xx}<,substitute_unknown_unset
+ 1: c>xx<t
+
/a|(?'X'b)c/replace=>$X<,substitute_unset_empty
cat
1: c><t
@@ -15081,9 +15111,21 @@
xbcom
1: x>b<om
+/a|(?'X'b)c/replace=>$Y<,substitute_unset_empty
+ cat
+Failed: error -49 at offset 3 in replacement: unknown substring
+ cat\=substitute_unknown_unset
+ 1: c><t
+ cat\=substitute_unknown_unset,-substitute_unset_empty
+Failed: error -55 at offset 3 in replacement: requested value is not set
+
/a|(b)c/replace=>$2<,substitute_unset_empty
cat
Failed: error -49 at offset 3 in replacement: unknown substring
+ cat\=substitute_unknown_unset
+ 1: c><t
+ cat\=substitute_unknown_unset,-substitute_unset_empty
+Failed: error -55 at offset 3 in replacement: requested value is not set
/()()()/use_offset_limit
\=ovector=11000000000