[Pcre-svn] [495] code/trunk: Implemented pcre2_code_copy().

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [495] code/trunk: Implemented pcre2_code_copy().
Revision: 495
          http://www.exim.org/viewvc/pcre2?view=rev&revision=495
Author:   ph10
Date:     2016-02-26 18:26:17 +0000 (Fri, 26 Feb 2016)
Log Message:
-----------
Implemented pcre2_code_copy().


Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/Makefile.am
    code/trunk/RunTest
    code/trunk/doc/index.html.src
    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_compile.c
    code/trunk/src/pcre2test.c
    code/trunk/testdata/testinput17
    code/trunk/testdata/testinput20
    code/trunk/testdata/testoutput17
    code/trunk/testdata/testoutput20


Added Paths:
-----------
    code/trunk/doc/pcre2_code_copy.3


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/ChangeLog    2016-02-26 18:26:17 UTC (rev 495)
@@ -69,7 +69,10 @@
 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
-----------------------------


Modified: code/trunk/Makefile.am
===================================================================
--- code/trunk/Makefile.am    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/Makefile.am    2016-02-26 18:26:17 UTC (rev 495)
@@ -25,6 +25,7 @@
   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 @@
   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 \


Modified: code/trunk/RunTest
===================================================================
--- code/trunk/RunTest    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/RunTest    2016-02-26 18:26:17 UTC (rev 495)
@@ -74,7 +74,7 @@
 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"


Modified: code/trunk/doc/index.html.src
===================================================================
--- code/trunk/doc/index.html.src    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/doc/index.html.src    2016-02-26 18:26:17 UTC (rev 495)
@@ -91,6 +91,9 @@
 <tr><td><a href="pcre2_callout_enumerate.html">pcre2_callout_enumerate</a></td>
     <td>&nbsp;&nbsp;Enumerate callouts in a compiled pattern</td></tr>


+<tr><td><a href="pcre2_code_copy.html">pcre2_code_copy</a></td>
+    <td>&nbsp;&nbsp;Copy a compiled pattern</td></tr>
+
 <tr><td><a href="pcre2_code_free.html">pcre2_code_free</a></td>
     <td>&nbsp;&nbsp;Free a compiled pattern</td></tr>



Added: code/trunk/doc/pcre2_code_copy.3
===================================================================
--- code/trunk/doc/pcre2_code_copy.3                            (rev 0)
+++ code/trunk/doc/pcre2_code_copy.3    2016-02-26 18:26:17 UTC (rev 495)
@@ -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 <pcre2.h>
+.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.


Modified: code/trunk/doc/pcre2api.3
===================================================================
--- code/trunk/doc/pcre2api.3    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/doc/pcre2api.3    2016-02-26 18:26:17 UTC (rev 495)
@@ -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 @@
 .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 @@
 (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,15 +1023,34 @@
 .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 <a href="#jitcompiling">
+.\" </a>
+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
 be referenced by the extraction functions. After running a match, you must not
@@ -1039,15 +1061,12 @@
 .\"
 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 @@
 textual error message from any error code.
 .
 .
+.\" HTML <a name="jitcompiling"></a>
 .SH "JUST-IN-TIME (JIT) COMPILATION"
 .rs
 .sp
@@ -3209,6 +3229,6 @@
 .rs
 .sp
 .nf
-Last updated: 25 February 2016
+Last updated: 26 February 2016
 Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2test.1
===================================================================
--- code/trunk/doc/pcre2test.1    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/doc/pcre2test.1    2016-02-26 18:26:17 UTC (rev 495)
@@ -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 @@
 command helps detect tests that are accidentally put in the wrong file.
 .sp
   #pop [<modifiers>]
+  #popcopy [<modifiers>]
 .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 <a href="#saverestore">
 .\" </a>
 below.
@@ -537,6 +538,7 @@
       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=<number>       test the stackguard feature
       tables=[0|1|2]            select internal tables
 .sp
@@ -895,13 +897,17 @@
 section entitled "Saving and restoring compiled patterns"
 .\" HTML <a href="#saverestore">
 .\" </a>
-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 <a name="subjectmodifiers"></a>
@@ -1590,11 +1596,15 @@
 .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 <filename>
 .sp
@@ -1614,7 +1624,8 @@
 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 <a href="#optionmodifiers">
 .\" </a>
 option-setting modifiers.
@@ -1634,6 +1645,10 @@
 .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.
 .
 .
 .


Modified: code/trunk/src/pcre2.h
===================================================================
--- code/trunk/src/pcre2.h    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/src/pcre2.h    2016-02-26 18:26:17 UTC (rev 495)
@@ -436,7 +436,9 @@
 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 @@
/* 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_)


Modified: code/trunk/src/pcre2.h.in
===================================================================
--- code/trunk/src/pcre2.h.in    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/src/pcre2.h.in    2016-02-26 18:26:17 UTC (rev 495)
@@ -436,7 +436,9 @@
 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 @@
/* 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_)


Modified: code/trunk/src/pcre2_compile.c
===================================================================
--- code/trunk/src/pcre2_compile.c    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/src/pcre2_compile.c    2016-02-26 18:26:17 UTC (rev 495)
@@ -730,6 +730,39 @@



 /*************************************************
+*               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               *
 *************************************************/



Modified: code/trunk/src/pcre2test.c
===================================================================
--- code/trunk/src/pcre2test.c    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/src/pcre2test.c    2016-02-26 18:26:17 UTC (rev 495)
@@ -353,7 +353,7 @@
 } 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 @@
   { "pattern",         CMD_PATTERN },
   { "perltest",        CMD_PERLTEST },
   { "pop",             CMD_POP },
+  { "popcopy",         CMD_POPCOPY },
   { "save",            CMD_SAVE },
   { "subject",         CMD_SUBJECT }};


@@ -427,9 +428,9 @@
 #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 @@
   { "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 @@


#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 @@
#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 @@
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 @@
      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 @@
      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 @@
 #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 @@
 #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 @@
 #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 @@
 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 @@
   ((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 @@
   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 @@
   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 @@
 /* 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 @@
   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 @@

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 @@

/* 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). */

Modified: code/trunk/testdata/testinput17
===================================================================
--- code/trunk/testdata/testinput17    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/testdata/testinput17    2016-02-26 18:26:17 UTC (rev 495)
@@ -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

Modified: code/trunk/testdata/testinput20
===================================================================
--- code/trunk/testdata/testinput20    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/testdata/testinput20    2016-02-26 18:26:17 UTC (rev 495)
@@ -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


Modified: code/trunk/testdata/testoutput17
===================================================================
--- code/trunk/testdata/testoutput17    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/testdata/testoutput17    2016-02-26 18:26:17 UTC (rev 495)
@@ -392,6 +392,15 @@
     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

Modified: code/trunk/testdata/testoutput20
===================================================================
--- code/trunk/testdata/testoutput20    2016-02-25 17:40:16 UTC (rev 494)
+++ code/trunk/testdata/testoutput20    2016-02-26 18:26:17 UTC (rev 495)
@@ -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 @@
 #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