diff --git a/ChangeLog b/ChangeLog index 1d42de4..92172a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -69,6 +69,9 @@ identification. a report of compiler warnings from Visual Studio 2013 and a few tests with gcc's -Wconversion (which still throws up a lot). +15. Implemented pcre2_code_copy(), and added pushcopy and #popcopy to pcre2test +for testing it. + Version 10.21 12-January-2016 ----------------------------- diff --git a/Makefile.am b/Makefile.am index 5977ba0..19bfb90 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ dist_html_DATA = \ doc/html/pcre2-config.html \ doc/html/pcre2.html \ doc/html/pcre2_callout_enumerate.html \ + doc/html/pcre2_code_copy.html \ doc/html/pcre2_code_free.html \ doc/html/pcre2_compile.html \ doc/html/pcre2_compile_context_copy.html \ @@ -105,6 +106,7 @@ dist_man_MANS = \ doc/pcre2-config.1 \ doc/pcre2.3 \ doc/pcre2_callout_enumerate.3 \ + doc/pcre2_code_copy.3 \ doc/pcre2_code_free.3 \ doc/pcre2_compile.3 \ doc/pcre2_compile_context_copy.3 \ diff --git a/RunTest b/RunTest index 120e9f9..290b43c 100755 --- a/RunTest +++ b/RunTest @@ -74,7 +74,7 @@ title16="Test 16: JIT-specific features when JIT is not available" title17="Test 17: JIT-specific features when JIT is available" title18="Test 18: Tests of the POSIX interface, excluding UTF/UCP" title19="Test 19: Tests of the POSIX interface with UTF/UCP" -title20="Test 20: Serialization tests" +title20="Test 20: Serialization and code copy tests" title21="Test 21: \C tests without UTF (supported for DFA matching)" title22="Test 22: \C tests with UTF (not supported for DFA matching)" title23="Test 23: \C disabled test" diff --git a/doc/index.html.src b/doc/index.html.src index f459657..703c298 100644 --- a/doc/index.html.src +++ b/doc/index.html.src @@ -91,6 +91,9 @@ in the library. pcre2_callout_enumerate   Enumerate callouts in a compiled pattern +pcre2_code_copy +   Copy a compiled pattern + pcre2_code_free   Free a compiled pattern diff --git a/doc/pcre2_code_copy.3 b/doc/pcre2_code_copy.3 new file mode 100644 index 0000000..270b3a6 --- /dev/null +++ b/doc/pcre2_code_copy.3 @@ -0,0 +1,30 @@ +.TH PCRE2_CODE_COPY 3 "26 February 2016" "PCRE2 10.22" +.SH NAME +PCRE2 - Perl-compatible regular expressions (revised API) +.SH SYNOPSIS +.rs +.sp +.B #include +.PP +.nf +.B pcre2_code *pcre2_code_copy(const pcre2_code *\fIcode\fP); +.fi +. +.SH DESCRIPTION +.rs +.sp +This function makes a copy of the memory used for a compiled pattern, excluding +any memory used by the JIT compiler. Without a subsequent call to +\fBpcre2_jit_compile()\fP, the copy can be used only for non-JIT matching. The +yield of the function is NULL if \fIcode\fP is NULL or if sufficient memory +cannot be obtained. +.P +There is a complete description of the PCRE2 native API in the +.\" HREF +\fBpcre2api\fP +.\" +page and a description of the POSIX API in the +.\" HREF +\fBpcre2posix\fP +.\" +page. diff --git a/doc/pcre2api.3 b/doc/pcre2api.3 index 7a091bd..0345121 100644 --- a/doc/pcre2api.3 +++ b/doc/pcre2api.3 @@ -1,4 +1,4 @@ -.TH PCRE2API 3 "25 February 2016" "PCRE2 10.22" +.TH PCRE2API 3 "26 February 2016" "PCRE2 10.22" .SH NAME PCRE2 - Perl-compatible regular expressions (revised API) .sp @@ -233,6 +233,8 @@ document for an overview of all the PCRE2 documentation. .rs .sp .nf +.B pcre2_code *pcre2_code_copy(const pcre2_code *\fIcode\fP); +.sp .B int pcre2_get_error_message(int \fIerrorcode\fP, PCRE2_UCHAR *\fIbuffer\fP, .B " PCRE2_SIZE \fIbufflen\fP);" .sp @@ -506,7 +508,8 @@ If JIT is being used, but the JIT compilation is not being done immediately, (perhaps waiting to see if the pattern is used often enough) similar logic is required. JIT compilation updates a pointer within the compiled code block, so a thread must gain unique write access to the pointer before calling -\fBpcre2_jit_compile()\fP. +\fBpcre2_jit_compile()\fP. Alternatively, \fBpcre2_code_copy()\fP can be used +to obtain a private copy of the compiled code. . . .SS "Context blocks" @@ -1020,14 +1023,33 @@ zero. .B " pcre2_compile_context *\fIccontext\fP);" .sp .B void pcre2_code_free(pcre2_code *\fIcode\fP); +.sp +.B pcre2_code *pcre2_code_copy(const pcre2_code *\fIcode\fP); .fi .P The \fBpcre2_compile()\fP function compiles a pattern into an internal form. -The pattern is defined by a pointer to a string of code units and a length, If +The pattern is defined by a pointer to a string of code units and a length. If the pattern is zero-terminated, the length can be specified as PCRE2_ZERO_TERMINATED. The function returns a pointer to a block of memory that -contains the compiled pattern and related data. The caller must free the memory -by calling \fBpcre2_code_free()\fP when it is no longer needed. +contains the compiled pattern and related data. +.P +If the compile context argument \fIccontext\fP is NULL, memory for the compiled +pattern is obtained by calling \fBmalloc()\fP. Otherwise, it is obtained from +the same memory function that was used for the compile context. The caller must +free the memory by calling \fBpcre2_code_free()\fP when it is no longer needed. +.P +The function \fBpcre2_code_copy()\fP makes a copy of the compiled code in new +memory, using the same memory allocator as was used for the original. However, +if the code has been processed by the JIT compiler (see +.\" HTML +.\" +below), +.\" +the JIT information cannot be copied (because it is position-dependent). +The new copy can initially be used only for non-JIT matching, though it can be +passed to \fBpcre2_jit_compile()\fP if required. The \fBpcre2_code_copy()\fP +function provides a way for individual threads in a multithreaded application +to acquire a private copy of shared compiled code. .P NOTE: When one of the matching functions is called, pointers to the compiled pattern and the subject string are set in the match data block so that they can @@ -1039,15 +1061,12 @@ match data block .\" have taken place. .P -If the compile context argument \fIccontext\fP is NULL, memory for the compiled -pattern is obtained by calling \fBmalloc()\fP. Otherwise, it is obtained from -the same memory function that was used for the compile context. -.P -The \fIoptions\fP argument contains various bit settings that affect the -compilation. It should be zero if no options are required. The available -options are described below. Some of them (in particular, those that are -compatible with Perl, but some others as well) can also be set and unset from -within the pattern (see the detailed description in the +The \fIoptions\fP argument for \fBpcre2_compile()\fP contains various bit +settings that affect the compilation. It should be zero if no options are +required. The available options are described below. Some of them (in +particular, those that are compatible with Perl, but some others as well) can +also be set and unset from within the pattern (see the detailed description in +the .\" HREF \fBpcre2pattern\fP .\" @@ -1470,6 +1489,7 @@ page. The \fBpcre2_get_error_message()\fP function can be called to obtain a textual error message from any error code. . . +.\" HTML .SH "JUST-IN-TIME (JIT) COMPILATION" .rs .sp @@ -3209,6 +3229,6 @@ Cambridge, England. .rs .sp .nf -Last updated: 25 February 2016 +Last updated: 26 February 2016 Copyright (c) 1997-2016 University of Cambridge. .fi diff --git a/doc/pcre2test.1 b/doc/pcre2test.1 index f6454f6..b7cc437 100644 --- a/doc/pcre2test.1 +++ b/doc/pcre2test.1 @@ -1,4 +1,4 @@ -.TH PCRE2TEST 1 "06 February 2016" "PCRE 10.22" +.TH PCRE2TEST 1 "26 February 2016" "PCRE 10.22" .SH NAME pcre2test - a program for testing Perl-compatible regular expressions. .SH SYNOPSIS @@ -306,9 +306,10 @@ test files that are also processed by \fBperltest.sh\fP. The \fB#perltest\fP command helps detect tests that are accidentally put in the wrong file. .sp #pop [] + #popcopy [] .sp -This command is used to manipulate the stack of compiled patterns, as described -in the section entitled "Saving and restoring compiled patterns" +These commands are used to manipulate the stack of compiled patterns, as +described in the section entitled "Saving and restoring compiled patterns" .\" HTML .\" below. @@ -537,6 +538,7 @@ about the pattern: posix use the POSIX API posix_nosub use the POSIX API with REG_NOSUB push push compiled pattern onto the stack + pushcopy push a copy onto the stack stackguard= test the stackguard feature tables=[0|1|2] select internal tables .sp @@ -895,13 +897,17 @@ facility is used when saving compiled patterns to a file, as described in the section entitled "Saving and restoring compiled patterns" .\" HTML .\" -below. +below. If \fBpushcopy\fP is used instead of \fBpush\fP, a copy of the compiled +pattern is stacked, leaving the original as current, ready to match the +following input lines. This provides a way of testing the +\fBpcre2_code_copy()\fP function. .\" -The \fBpush\fP modifier is incompatible with compilation modifiers such as -\fBglobal\fP that act at match time. Any that are specified are ignored, with a -warning message, except for \fBreplace\fP, which causes an error. Note that, -\fBjitverify\fP, which is allowed, does not carry through to any subsequent -matching that uses this pattern. +The \fBpush\fP and \fBpushcopy \fP modifiers are incompatible with compilation +modifiers such as \fBglobal\fP that act at match time. Any that are specified +are ignored (for the stacked copy), with a warning message, except for +\fBreplace\fP, which causes an error. Note that \fBjitverify\fP, which is +allowed, does not carry through to any subsequent matching that uses a stacked +pattern. . . .\" HTML @@ -1590,11 +1596,15 @@ can be used to test these functions. .P When a pattern with \fBpush\fP modifier is successfully compiled, it is pushed onto a stack of compiled patterns, and \fBpcre2test\fP expects the next line to -contain a new pattern (or command) instead of a subject line. By this means, a -number of patterns can be compiled and retained. The \fBpush\fP modifier is -incompatible with \fBposix\fP, and control modifiers that act at match time are -ignored (with a message). The \fBjitverify\fP modifier applies only at compile -time. The command +contain a new pattern (or command) instead of a subject line. By contrast, +the \fBpushcopy\fP modifier causes a copy of the compiled pattern to be +stacked, leaving the original available for immediate matching. By using +\fBpush\fP and/or \fBpushcopy\fP, a number of patterns can be compiled and +retained. These modifiers are incompatible with \fBposix\fP, and control +modifiers that act at match time are ignored (with a message) for the stacked +patterns. The \fBjitverify\fP modifier applies only at compile time. +.P +The command .sp #save .sp @@ -1614,7 +1624,8 @@ modifier list containing only control modifiers .\" that act after a pattern has been compiled. In particular, \fBhex\fP, -\fBposix\fP, \fBposix_nosub\fP, and \fBpush\fP are not allowed, nor are any +\fBposix\fP, \fBposix_nosub\fP, \fBpush\fP, and \fBpushcopy\fP are not allowed, +nor are any .\" HTML .\" option-setting modifiers. @@ -1634,6 +1645,10 @@ reloads two patterns. .sp If \fBjitverify\fP is used with #pop, it does not automatically imply \fBjit\fP, which is different behaviour from when it is used on a pattern. +.P +The #popcopy command is analagous to the \fBpushcopy\fP modifier in that it +makes current a copy of the topmost stack pattern, leaving the original still +on the stack. . . . diff --git a/src/pcre2.h b/src/pcre2.h index 6c2b31e..b2153d9 100644 --- a/src/pcre2.h +++ b/src/pcre2.h @@ -436,7 +436,9 @@ PCRE2_EXP_DECL int pcre2_set_recursion_memory_management( \ PCRE2_EXP_DECL \ pcre2_code *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, \ int *, PCRE2_SIZE *, pcre2_compile_context *); \ -PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); +PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); \ +PCRE2_EXP_DECL \ + pcre2_code *pcre2_code_copy(const pcre2_code *); /* Functions that give information about a compiled pattern. */ @@ -585,6 +587,7 @@ pcre2_compile are called by application code. */ /* Functions: the complete list in alphabetical order */ #define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_) +#define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_) #define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_) #define pcre2_compile PCRE2_SUFFIX(pcre2_compile_) #define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_) diff --git a/src/pcre2.h.in b/src/pcre2.h.in index 49f1909..56c9651 100644 --- a/src/pcre2.h.in +++ b/src/pcre2.h.in @@ -436,7 +436,9 @@ PCRE2_EXP_DECL int pcre2_set_recursion_memory_management( \ PCRE2_EXP_DECL \ pcre2_code *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, \ int *, PCRE2_SIZE *, pcre2_compile_context *); \ -PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); +PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); \ +PCRE2_EXP_DECL \ + pcre2_code *pcre2_code_copy(const pcre2_code *); /* Functions that give information about a compiled pattern. */ @@ -585,6 +587,7 @@ pcre2_compile are called by application code. */ /* Functions: the complete list in alphabetical order */ #define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_) +#define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_) #define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_) #define pcre2_compile PCRE2_SUFFIX(pcre2_compile_) #define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_) diff --git a/src/pcre2_compile.c b/src/pcre2_compile.c index 9841d02..baaff3d 100644 --- a/src/pcre2_compile.c +++ b/src/pcre2_compile.c @@ -729,6 +729,39 @@ static const uint8_t opcode_possessify[] = { +/************************************************* +* Copy compiled code * +*************************************************/ + +/* Compiled JIT code cannot be copied, so the new compiled block has no +associated JIT data. */ + +PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION +pcre2_code_copy(const pcre2_code *code) +{ +PCRE2_SIZE* ref_count; +pcre2_code *newcode; + +if (code == NULL) return NULL; +newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data); +if (newcode == NULL) return NULL; +memcpy(newcode, code, code->blocksize); +newcode->executable_jit = NULL; + +/* If the code is one that has been deserialized, increment the reference count +in the decoded tables. */ + +if ((code->flags & PCRE2_DEREF_TABLES) != 0) + { + ref_count = (PCRE2_SIZE *)(code->tables + tables_length); + (*ref_count)++; + } + +return newcode; +} + + + /************************************************* * Free compiled code * *************************************************/ diff --git a/src/pcre2test.c b/src/pcre2test.c index da0ccfb..cc961a7 100644 --- a/src/pcre2test.c +++ b/src/pcre2test.c @@ -353,7 +353,7 @@ typedef struct cmdstruct { } cmdstruct; enum { CMD_FORBID_UTF, CMD_LOAD, CMD_NEWLINE_DEFAULT, CMD_PATTERN, - CMD_PERLTEST, CMD_POP, CMD_SAVE, CMD_SUBJECT, CMD_UNKNOWN }; + CMD_PERLTEST, CMD_POP, CMD_POPCOPY, CMD_SAVE, CMD_SUBJECT, CMD_UNKNOWN }; static cmdstruct cmdlist[] = { { "forbid_utf", CMD_FORBID_UTF }, @@ -362,6 +362,7 @@ static cmdstruct cmdlist[] = { { "pattern", CMD_PATTERN }, { "perltest", CMD_PERLTEST }, { "pop", CMD_POP }, + { "popcopy", CMD_POPCOPY }, { "save", CMD_SAVE }, { "subject", CMD_SUBJECT }}; @@ -427,9 +428,9 @@ so many of them that they are split into two fields. */ #define CTL_POSIX 0x00400000u #define CTL_POSIX_NOSUB 0x00800000u #define CTL_PUSH 0x01000000u -#define CTL_STARTCHAR 0x02000000u -#define CTL_ZERO_TERMINATE 0x04000000u -/* Spare 0x08000000u */ +#define CTL_PUSHCOPY 0x02000000u +#define CTL_STARTCHAR 0x04000000u +#define CTL_ZERO_TERMINATE 0x08000000u /* Spare 0x10000000u */ /* Spare 0x20000000u */ #define CTL_NL_SET 0x40000000u /* Informational */ @@ -603,6 +604,7 @@ static modstruct modlist[] = { { "posix_nosub", MOD_PAT, MOD_CTL, CTL_POSIX|CTL_POSIX_NOSUB, PO(control) }, { "ps", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) }, { "push", MOD_PAT, MOD_CTL, CTL_PUSH, PO(control) }, + { "pushcopy", MOD_PAT, MOD_CTL, CTL_PUSHCOPY, 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) }, @@ -644,7 +646,7 @@ static modstruct modlist[] = { #define PUSH_SUPPORTED_COMPILE_CONTROLS ( \ CTL_BINCODE|CTL_CALLOUT_INFO|CTL_FULLBINCODE|CTL_HEXPAT|CTL_INFO| \ - CTL_JITVERIFY|CTL_MEMORY|CTL_PUSH|CTL_BSR_SET|CTL_NL_SET) + CTL_JITVERIFY|CTL_MEMORY|CTL_PUSH|CTL_PUSHCOPY|CTL_BSR_SET|CTL_NL_SET) #define PUSH_SUPPORTED_COMPILE_CONTROLS2 (0) @@ -653,9 +655,10 @@ static modstruct modlist[] = { #define PUSH_COMPILE_ONLY_CONTROLS CTL_JITVERIFY #define PUSH_COMPILE_ONLY_CONTROLS2 (0) -/* Controls that are forbidden with #pop. */ +/* Controls that are forbidden with #pop or #popcopy. */ -#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_POSIX_NOSUB|CTL_PUSH) +#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_POSIX_NOSUB|CTL_PUSH| \ + CTL_PUSHCOPY) /* Pattern controls that are mutually exclusive. At present these are all in the first control word. Note that CTL_POSIX_NOSUB is always accompanied by @@ -664,6 +667,7 @@ CTL_POSIX, so it doesn't need its own entries. */ static uint32_t exclusive_pat_controls[] = { CTL_POSIX | CTL_HEXPAT, CTL_POSIX | CTL_PUSH, + CTL_POSIX | CTL_PUSHCOPY, CTL_EXPAND | CTL_HEXPAT }; /* Data controls that are mutually exclusive. At present these are all in the @@ -945,6 +949,22 @@ are supported. */ a = pcre2_callout_enumerate_32(compiled_code32, \ (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) \ + if (test_mode == PCRE8_MODE) \ + G(a,8) = pcre2_code_copy_8(b); \ + else if (test_mode == PCRE16_MODE) \ + G(a,16) = pcre2_code_copy_16(b); \ + else \ + G(a,32) = pcre2_code_copy_32(b) + +#define PCRE2_CODE_COPY_TO_VOID(a,b) \ + if (test_mode == PCRE8_MODE) \ + a = (void *)pcre2_code_copy_8(G(b,8)); \ + else if (test_mode == PCRE16_MODE) \ + a = (void *)pcre2_code_copy_16(G(b,16)); \ + else \ + a = (void *)pcre2_code_copy_32(G(b,32)) + #define PCRE2_COMPILE(a,b,c,d,e,f,g) \ if (test_mode == PCRE8_MODE) \ G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g); \ @@ -1396,6 +1416,18 @@ the three different cases. */ a = G(pcre2_callout_enumerate,BITTWO)(G(compiled_code,BITTWO), \ (int (*)(struct G(pcre2_callout_enumerate_block_,BITTWO) *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + G(a,BITONE) = G(pcre2_code_copy_,BITONE)(b); \ + else \ + G(a,BITTWO) = G(pcre2_code_copy_,BITTWO)(b) + +#define PCRE2_CODE_COPY_TO_VOID(a,b) \ + if (test_mode == G(G(PCRE,BITONE),_MODE)) \ + a = (void *)G(pcre2_code_copy_,BITONE)(G(b,BITONE)); \ + else \ + a = (void *)G(pcre2_code_copy_,BITTWO)(G(b,BITTWO)) + #define PCRE2_COMPILE(a,b,c,d,e,f,g) \ if (test_mode == G(G(PCRE,BITONE),_MODE)) \ G(a,BITONE) = G(pcre2_compile_,BITONE)(G(b,BITONE),c,d,e,f,g); \ @@ -1731,6 +1763,8 @@ the three different cases. */ #define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ a = pcre2_callout_enumerate_8(compiled_code8, \ (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,8) = pcre2_code_copy_8(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_8(G(b,8)) #define PCRE2_COMPILE(a,b,c,d,e,f,g) \ G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g) #define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ @@ -1824,6 +1858,8 @@ the three different cases. */ #define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ a = pcre2_callout_enumerate_16(compiled_code16, \ (int (*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,16) = pcre2_code_copy_16(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_16(G(b,16)) #define PCRE2_COMPILE(a,b,c,d,e,f,g) \ G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g) #define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ @@ -1917,6 +1953,8 @@ the three different cases. */ #define PCRE2_CALLOUT_ENUMERATE(a,b,c) \ a = pcre2_callout_enumerate_32(compiled_code32, \ (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c) +#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,32) = pcre2_code_copy_32(b) +#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_32(G(b,32)) #define PCRE2_COMPILE(a,b,c,d,e,f,g) \ G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g) #define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \ @@ -3584,7 +3622,7 @@ Returns: nothing static void 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%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%s%s", before, ((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "", ((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "", @@ -3613,6 +3651,7 @@ 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 ((controls & CTL_POSIX) != 0)? " posix" : "", ((controls & CTL_POSIX_NOSUB) != 0)? " posix_nosub" : "", ((controls & CTL_PUSH) != 0)? " push" : "", + ((controls & CTL_PUSHCOPY) != 0)? " pushcopy" : "", ((controls & CTL_STARTCHAR) != 0)? " startchar" : "", ((controls2 & CTL2_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "", ((controls2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)? " substitute_overflow_length" : "", @@ -4260,11 +4299,12 @@ switch(cmd) local_newline_default = first_listed_newline; break; - /* Pop a compiled pattern off the stack. Modifiers that do not affect the - compiled pattern (e.g. to give information) are permitted. The default + /* Pop or copy a compiled pattern off the stack. Modifiers that do not affect + the compiled pattern (e.g. to give information) are permitted. The default pattern modifiers are ignored. */ case CMD_POP: + case CMD_POPCOPY: if (patstacknext <= 0) { fprintf(outfile, "** Can't pop off an empty stack\n"); @@ -4273,7 +4313,16 @@ switch(cmd) memset(&pat_patctl, 0, sizeof(patctl)); /* Completely unset */ if (!decode_modifiers(argptr, CTX_POPPAT, &pat_patctl, NULL)) return PR_SKIP; - SET(compiled_code, patstack[--patstacknext]); + + if (cmd == CMD_POP) + { + SET(compiled_code, patstack[--patstacknext]); + } + else + { + PCRE2_CODE_COPY_FROM_VOID(compiled_code, patstack[patstacknext - 1]); + } + if (pat_patctl.jit != 0) { PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit); @@ -4769,7 +4818,7 @@ if ((pat_patctl.control & CTL_POSIX) != 0) /* Handle compiling via the native interface. Controls that act later are ignored with "push". Replacements are locked out. */ -if ((pat_patctl.control & CTL_PUSH) != 0) +if ((pat_patctl.control & (CTL_PUSH|CTL_PUSHCOPY)) != 0) { if (pat_patctl.replacement[0] != 0) { @@ -4972,6 +5021,19 @@ if ((pat_patctl.control & CTL_PUSH) != 0) SET(compiled_code, NULL); } +/* The "pushcopy" control is similar, but pushes a copy of the pattern. This +tests the pcre2_code_copy() function. */ + +if ((pat_patctl.control & CTL_PUSHCOPY) != 0) + { + if (patstacknext >= PATSTACKSIZE) + { + fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE); + return PR_ABEND; + } + PCRE2_CODE_COPY_TO_VOID(patstack[patstacknext++], compiled_code); + } + return PR_OK; } @@ -5116,10 +5178,10 @@ if (f != NULL) fprintf(f, "--->"); PCHARS(pre_start, cb->subject, 0, cb->start_match, utf, f); -/* If a lookbehind is involved, the current position may be earlier than the +/* If a lookbehind is involved, the current position may be earlier than the match start. If so, use the match start instead. */ -current_position = (cb->current_position >= cb->start_match)? +current_position = (cb->current_position >= cb->start_match)? cb->current_position : cb->start_match; /* The subject between the match start and the current position. */ @@ -5129,7 +5191,7 @@ PCHARS(post_start, cb->subject, cb->start_match, /* Print from the current position to the end. */ -PCHARSV(cb->subject, current_position, cb->subject_length - current_position, +PCHARSV(cb->subject, current_position, cb->subject_length - current_position, utf, f); /* Calculate the total subject printed length (no print). */ diff --git a/testdata/testinput17 b/testdata/testinput17 index 1474eb9..c60b31e 100644 --- a/testdata/testinput17 +++ b/testdata/testinput17 @@ -213,6 +213,12 @@ #pop jit,jitverify abcdef +/abcd/pushcopy,jitverify + abcd + +#pop jitverify + abcd + # Test pattern compilation /(?:a|b|c|d|e)(?R)/jit=1 diff --git a/testdata/testinput20 b/testdata/testinput20 index 9ec3174..c920e2a 100644 --- a/testdata/testinput20 +++ b/testdata/testinput20 @@ -1,5 +1,5 @@ -# This set of tests exercises the serialization/deserialization functions in -# the library. It does not use UTF or JIT. +# This set of tests exercises the serialization/deserialization and code copy +# functions in the library. It does not use UTF or JIT. #forbid_utf @@ -59,5 +59,33 @@ #pop should give an error pqr + +/abcd/pushcopy + abcd + +#pop + abcd + +#pop should give an error + +/abcd/push +#popcopy + abcd + +#pop + abcd + +/abcd/push +#save testsaved1 +#pop should give an error + +#load testsaved1 +#popcopy + abcd + +#pop + abcd + +#pop should give an error # End of testinput20 diff --git a/testdata/testoutput17 b/testdata/testoutput17 index 0def438..288b0d2 100644 --- a/testdata/testoutput17 +++ b/testdata/testoutput17 @@ -392,6 +392,15 @@ JIT compilation was successful abcdef 0: def (JIT) +/abcd/pushcopy,jitverify +** Applies only to compile when pattern is stacked with 'push': jitverify + abcd + 0: abcd (JIT) + +#pop jitverify + abcd + 0: abcd + # Test pattern compilation /(?:a|b|c|d|e)(?R)/jit=1 diff --git a/testdata/testoutput20 b/testdata/testoutput20 index e923080..952b0bb 100644 --- a/testdata/testoutput20 +++ b/testdata/testoutput20 @@ -1,5 +1,5 @@ -# This set of tests exercises the serialization/deserialization functions in -# the library. It does not use UTF or JIT. +# This set of tests exercises the serialization/deserialization and code copy +# functions in the library. It does not use UTF or JIT. #forbid_utf @@ -97,5 +97,42 @@ Serialization failed: error -30: patterns do not all use the same character tabl #pop should give an error ** Can't pop off an empty stack pqr + +/abcd/pushcopy + abcd + 0: abcd + +#pop + abcd + 0: abcd + +#pop should give an error +** Can't pop off an empty stack + +/abcd/push +#popcopy + abcd + 0: abcd + +#pop + abcd + 0: abcd + +/abcd/push +#save testsaved1 +#pop should give an error +** Can't pop off an empty stack + +#load testsaved1 +#popcopy + abcd + 0: abcd + +#pop + abcd + 0: abcd + +#pop should give an error +** Can't pop off an empty stack # End of testinput20