Preliminary substitute function (not yet tested or documented).

This commit is contained in:
ph10 2014-11-08 16:09:24 +00:00
parent 9b3d0814fc
commit 7dd909584e
7 changed files with 310 additions and 20 deletions

View File

@ -314,6 +314,7 @@ COMMON_SOURCES = \
src/pcre2_pattern_info.c \
src/pcre2_string_utils.c \
src/pcre2_study.c \
src/pcre2_substitute.c \
src/pcre2_substring.c \
src/pcre2_tables.c \
src/pcre2_ucd.c \

View File

@ -7,7 +7,7 @@ PCRE2 - Perl-compatible regular expressions (revised API)
.B #include <pcre2.h>
.PP
.nf
.B pcre2_match_data_create_from_pattern(pcre2_code *\fIcode\fP,
.B pcre2_match_data_create_from_pattern(const pcre2_code *\fIcode\fP,
.B " pcre2_general_context *\fIgcontext\fP);"
.fi
.

View File

@ -1,4 +1,4 @@
.TH PCRE2API 3 "03 November 2014" "PCRE2 10.00"
.TH PCRE2API 3 "08 November 2014" "PCRE2 10.00"
.SH NAME
PCRE2 - Perl-compatible regular expressions (revised API)
.sp
@ -25,7 +25,7 @@ document for an overview of all the PCRE2 documentation.
.B pcre2_match_data_create(uint32_t \fIovecsize\fP,
.B " pcre2_general_context *\fIgcontext\fP);"
.sp
.B pcre2_match_data_create_from_pattern(pcre2_code *\fIcode\fP,
.B pcre2_match_data_create_from_pattern(const pcre2_code *\fIcode\fP,
.B " pcre2_general_context *\fIgcontext\fP);"
.sp
.B int pcre2_match(const pcre2_code *\fIcode\fP, PCRE2_SPTR \fIsubject\fP,
@ -178,14 +178,14 @@ document for an overview of all the PCRE2 documentation.
.B int pcre2_jit_match(const pcre2_code *\fIcode\fP, PCRE2_SPTR \fIsubject\fP,
.B " PCRE2_SIZE \fIlength\fP, PCRE2_SIZE \fIstartoffset\fP,"
.B " uint32_t \fIoptions\fP, pcre2_match_data *\fImatch_data\fP,"
.B " pcre2_match_context *\fImcontext\fP, pcre2_jit_stack *\fIjit_stack\fP);"
.B " pcre2_match_context *\fImcontext\fP);"
.sp
.B void pcre2_jit_free_unused_memory(pcre2_general_context *\fIgcontext\fP);
.sp
.B pcre2_jit_stack *pcre2_jit_stack_create(pcre2_general_context *\fIgcontext\fP,
.B " PCRE2_SIZE \fIstartsize\fP, PCRE2_SIZE \fImaxsize\fP);"
.sp
.B void pcre2_jit_stack_assign(const pcre2_code *\fIcode\fP,
.B void pcre2_jit_stack_assign(pcre2_match_context *\fImcontext\fP,
.B " pcre2_jit_callback \fIcallback_function\fP, void *\fIcallback_data\fP);"
.sp
.B void pcre2_jit_stack_free(pcre2_jit_stack *\fIjit_stack\fP);
@ -783,8 +783,9 @@ units long. (The exact length needed can be found by calling
\fBpcre2_config()\fP with \fBwhere\fP set to NULL.) The buffer is filled with a
string that contains the name of the architecture for which the JIT compiler is
configured, for example "x86 32bit (little endian + unaligned)". If JIT support
is not available, PCRE2_ERROR_BADOPTION is returned, otherwise the length of
the string, in code units, is returned.
is not available, PCRE2_ERROR_BADOPTION is returned, otherwise the number of
code units used is returned. This is the length of the string, plus one unit
for the terminating zero.
.sp
PCRE2_CONFIG_LINKSIZE
.sp
@ -851,8 +852,8 @@ units long. (The exact length needed can be found by calling
\fBpcre2_config()\fP with \fBwhere\fP set to NULL.) If PCRE2 has been compiled
without Unicode support, the buffer is filled with the text "Unicode not
supported". Otherwise, the Unicode version string (for example, "7.0.0") is
inserted. The string is zero-terminated. The function returns the length of the
string in code units.
inserted. The number of code units used is returned. This is the length of the
string plus one unit for the terminating zero.
.sp
PCRE2_CONFIG_UNICODE
.sp
@ -864,8 +865,9 @@ otherwise it is set to zero. Unicode support implies UTF support.
The \fIwhere\fP argument should point to a buffer that is at least 12 code
units long. (The exact length needed can be found by calling
\fBpcre2_config()\fP with \fBwhere\fP set to NULL.) The buffer is filled with
the PCRE2 version string, zero-terminated. The length of the string (in code
units) is returned.
the PCRE2 version string, zero-terminated. The number of code units used is
returned. This is the length of the string plus one unit for the terminating
zero.
.
.
.\" HTML <a name="compiling"></a>
@ -1261,14 +1263,14 @@ textual error message from any error code.
.B int pcre2_jit_match(const pcre2_code *\fIcode\fP, PCRE2_SPTR \fIsubject\fP,
.B " PCRE2_SIZE \fIlength\fP, PCRE2_SIZE \fIstartoffset\fP,"
.B " uint32_t \fIoptions\fP, pcre2_match_data *\fImatch_data\fP,"
.B " pcre2_match_context *\fImcontext\fP, pcre2_jit_stack *\fIjit_stack\fP);"
.B " pcre2_match_context *\fImcontext\fP);"
.sp
.B void pcre2_jit_free_unused_memory(pcre2_general_context *\fIgcontext\fP);
.sp
.B pcre2_jit_stack *pcre2_jit_stack_create(pcre2_general_context *\fIgcontext\fP,
.B " PCRE2_SIZE \fIstartsize\fP, PCRE2_SIZE \fImaxsize\fP);"
.sp
.B void pcre2_jit_stack_assign(const pcre2_code *\fIcode\fP,
.B void pcre2_jit_stack_assign(pcre2_match_context *\fImcontext\fP,
.B " pcre2_jit_callback \fIcallback_function\fP, void *\fIcallback_data\fP);"
.sp
.B void pcre2_jit_stack_free(pcre2_jit_stack *\fIjit_stack\fP);
@ -1642,7 +1644,7 @@ pattern with the JIT compiler does not alter the value returned by this option.
.B pcre2_match_data_create(uint32_t \fIovecsize\fP,
.B " pcre2_general_context *\fIgcontext\fP);"
.sp
.B pcre2_match_data_create_from_pattern(pcre2_code *\fIcode\fP,
.B pcre2_match_data_create_from_pattern(const pcre2_code *\fIcode\fP,
.B " pcre2_general_context *\fIgcontext\fP);"
.sp
.B void pcre2_match_data_free(pcre2_match_data *\fImatch_data\fP);
@ -2631,6 +2633,6 @@ Cambridge CB2 3QH, England.
.rs
.sp
.nf
Last updated: 03 November 2014
Last updated: 08 November 2014
Copyright (c) 1997-2014 University of Cambridge.
.fi

View File

@ -125,8 +125,8 @@ D is inspected during pcre2_dfa_match() execution
#define PCRE2_JIT_PARTIAL_HARD 0x00000004u
/* These are for pcre2_match() and pcre2_dfa_match(). Note that PCRE2_ANCHORED,
PCRE2_NO_START_OPTIMIZE, and PCRE2_NO_UTF_CHECK can also be passed to these
functions, so take care not to define synonyms by mistake. */
and PCRE2_NO_UTF_CHECK can also be passed to these functions, so take care not
to define synonyms by mistake. */
#define PCRE2_NOTBOL 0x00000001u
#define PCRE2_NOTEOL 0x00000002u
@ -140,6 +140,10 @@ functions, so take care not to define synonyms by mistake. */
#define PCRE2_DFA_RESTART 0x00000040u
#define PCRE2_DFA_SHORTEST 0x00000080u
/* This is an additional option for pcre2_substitute(). */
#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
/* Newline and \R settings, for use in compile contexts. The newline values
must be kept in step with values set in config.h and both sets must all be
greater than zero. */
@ -406,7 +410,8 @@ PCRE2_EXP_DECL \
pcre2_match_data *pcre2_match_data_create(uint32_t, \
pcre2_general_context *); \
PCRE2_EXP_DECL \
pcre2_match_data *pcre2_match_data_create_from_pattern(pcre2_code *, \
pcre2_match_data *pcre2_match_data_create_from_pattern(\
const pcre2_code *, \
pcre2_general_context *); \
PCRE2_EXP_DECL int pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, \
PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
@ -447,6 +452,16 @@ PCRE2_EXP_DECL int pcre2_substring_list_get(pcre2_match_data *, \
PCRE2_UCHAR ***, PCRE2_SIZE **);
/* Convenience function for match + substitute. */
#define PCRE2_SUBSTITUTE_FUNCTION \
PCRE2_EXP_DECL int pcre2_substitute(const pcre2_code *, \
PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
pcre2_match_data *, pcre2_match_context *, \
PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *, \
PCRE2_SIZE *);
/* Functions for JIT processing */
#define PCRE2_JIT_FUNCTIONS \
@ -550,6 +565,7 @@ pcre2_compile are called by application code. */
#define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_)
#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_)
#define pcre2_substitute PCRE2_SUFFIX(pcre2_substitute_)
#define pcre2_substring_copy_byname PCRE2_SUFFIX(pcre2_substring_copy_byname_)
#define pcre2_substring_copy_bynumber PCRE2_SUFFIX(pcre2_substring_copy_bynumber_)
#define pcre2_substring_free PCRE2_SUFFIX(pcre2_substring_free_)
@ -576,6 +592,7 @@ PCRE2_MATCH_CONTEXT_FUNCTIONS \
PCRE2_COMPILE_FUNCTIONS \
PCRE2_PATTERN_INFO_FUNCTIONS \
PCRE2_MATCH_FUNCTIONS \
PCRE2_SUBSTITUTE_FUNCTION \
PCRE2_SUBSTRING_FUNCTIONS \
PCRE2_JIT_FUNCTIONS \
PCRE2_OTHER_FUNCTIONS

View File

@ -73,7 +73,7 @@ return yield;
*************************************************/
PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
pcre2_match_data_create_from_pattern(pcre2_code *code,
pcre2_match_data_create_from_pattern(const pcre2_code *code,
pcre2_general_context *gcontext)
{
return pcre2_match_data_create(((pcre2_real_code *)code)->top_bracket + 1,

269
src/pcre2_substitute.c Normal file
View File

@ -0,0 +1,269 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2014 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pcre2_internal.h"
/*************************************************
* Match and substitute *
*************************************************/
/* This function applies a compiled re to a subject string and creates a new
string with substitutione. The first 7 arguments are the same as for
pcre2_match(). Either string length may be PCRE2_ZERO_TERMINATED.
Arguments:
code points to the compiled expression
subject points to the subject string
length length of subject string (may contain binary zeros)
start_offset where to start in the subject string
options option bits
match_data points to a match_data block, or is NULL
context points a PCRE2 context
replacement points to the replacement string
rlength length of replacement string
buffer where to put the substituted string
blength points to length of buffer; updated to length of string
Returns: > 0 number of substitutions made
< 0 an error code, including PCRE2_ERROR_NOMATCH if no match
*/
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength,
PCRE2_UCHAR *buffer, PCRE2_SIZE *blength)
{
int rc = 0;
int subs = 0;
uint32_t ovector_count;
uint32_t goptions = 0;
BOOL match_data_created = FALSE;
BOOL global = FALSE;
PCRE2_SIZE buff_offset, lengthleft, endlength;
PCRE2_SIZE *ovector;
/* If no match data block is provided, create one. */
if (match_data == NULL)
{
pcre2_general_context *gcontext = (mcontext == NULL)?
(pcre2_general_context *)code :
(pcre2_general_context *)mcontext;
match_data = pcre2_match_data_create_from_pattern(code, gcontext);
if (match_data == NULL) return PCRE2_ERROR_NOMEMORY;
match_data_created = TRUE;
}
ovector = pcre2_get_ovector_pointer(match_data);
ovector_count = pcre2_get_ovector_count(match_data);
/* Notice the global option and remove it from the options that are passed to
pcre2_match(). */
if ((options & PCRE2_SUBSTITUTE_GLOBAL) != 0)
{
options &= ~PCRE2_SUBSTITUTE_GLOBAL;
global = TRUE;
}
/* Find lengths of zero-terminated strings. */
if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
/* Copy up to the start offset */
if (start_offset > *blength) goto NOROOM;
memcpy(buffer, subject, start_offset * (PCRE2_CODE_UNIT_WIDTH/8));
buff_offset = start_offset;
lengthleft = *blength - start_offset;
/* Loop for global substituting. */
do
{
PCRE2_SIZE i;
rc = pcre2_match(code, subject, length, start_offset, options|goptions,
match_data, mcontext);
if (rc < 0)
{
if (goptions == 0 || rc != PCRE2_ERROR_NOMATCH || start_offset >= length)
break;
start_offset++;
if ((code->overall_options & PCRE2_UTF) != 0)
{
#if PCRE2_CODE_UNIT_WIDTH == 8
while (start_offset < length && (subject[start_offset] & 0xc0) == 0x80)
start_offset++;
#elif PCRE2_CODE_UNIT_WIDTH == 16
while (start_offset < length &&
(subject[start_offset] & 0xfc00) == 0xdc00)
start_offset++;
#endif
}
goptions = 0;
continue;
}
subs++;
if (rc == 0) rc = ovector_count;
endlength = ovector[0] - start_offset;
if (endlength >= lengthleft) goto NOROOM;
memcpy(buffer + buff_offset, subject + start_offset,
endlength*(PCRE2_CODE_UNIT_WIDTH/8));
buff_offset += endlength;
lengthleft -= endlength;
for (i = 0; i < rlength; i++)
{
if (replacement[i] == CHAR_DOLLAR_SIGN && i != rlength - 1)
{
int group = -1;
int n = 0;
BOOL inparens = FALSE;
PCRE2_SIZE j = i + 1;
PCRE2_SIZE sublength;
PCRE2_UCHAR next = replacement[j];
PCRE2_UCHAR name[33];
if (next == CHAR_LEFT_CURLY_BRACKET)
{
if (j == rlength - 1) goto LITERAL;
inparens = TRUE;
next = replacement[++j];
}
if (next >= CHAR_0 && next <= CHAR_9)
{
group = next - CHAR_0;
while (j < rlength - 1)
{
next = replacement[++j];
if (next < CHAR_0 || next > CHAR_9) break;
group = group * 10 + next - CHAR_0;
}
}
else
{
const uint8_t *ctypes = code->tables + ctypes_offset;
while (MAX_255(next) && (ctypes[next] & ctype_word) != 0)
{
name[n++] = next;
if (n > 32) goto LITERAL;
if (j == rlength - 1) break;
next = replacement[++j];
}
name[n] = 0;
}
if (inparens)
{
if (j == rlength || next != CHAR_RIGHT_CURLY_BRACKET) goto LITERAL;
}
else j--; /* Last code unit of name/number */
/* Have found a syntactically correct group number or name. */
i = j; /* Where to continue from */
if (group < 0)
rc = pcre2_substring_copy_byname(match_data, name,
buffer + buff_offset, &sublength);
else
rc = pcre2_substring_copy_bynumber(match_data, group,
buffer + buff_offset, &sublength);
if (rc < 0) goto EXIT;
buff_offset += sublength;
lengthleft -= sublength;
}
/* Handle a literal code unit */
else
{
LITERAL:
if (lengthleft-- < 1) goto NOROOM;
buffer[buff_offset++] = replacement[i];
}
}
/* 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,
do the magic for global matches. */
start_offset = ovector[1];
goptions = (ovector[0] != ovector[1])? 0 :
PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART;
} while (global); /* Repeat "do" loop */
/* No match is a "normal" end; copy the rest of the subject and return the
number of substitutions. */
if (rc == PCRE2_ERROR_NOMATCH)
{
rc = subs;
endlength = length - start_offset;
if (endlength + 1 >= lengthleft) goto NOROOM;
memcpy(buffer + buff_offset, subject + start_offset,
endlength*(PCRE2_CODE_UNIT_WIDTH/8));
buff_offset += endlength;
buffer[buff_offset] = 0;
*blength = buff_offset;
}
EXIT:
if (match_data_created) pcre2_match_data_free(match_data);
return rc;
NOROOM:
rc = PCRE2_ERROR_NOMEMORY;
goto EXIT;
}
/* End of pcre2_substitute.c */

View File

@ -472,7 +472,8 @@ Arguments:
stringname the name whose number is required
Returns: the number of the named parenthesis, or a negative number
(PCRE2_ERROR_NOSUBSTRING) if not found
PCRE2_ERROR_NOSUBSTRING if not found
PCRE2_ERROR_NOUNIQUESUBSTRING if not unique
*/
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION