[Pcre-svn] [128] code/trunk: Improve test coverage; minor t…

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [128] code/trunk: Improve test coverage; minor typo in JIT test and other minor buglets fixed.
Revision: 128
          http://www.exim.org/viewvc/pcre2?view=rev&revision=128
Author:   ph10
Date:     2014-10-31 12:34:34 +0000 (Fri, 31 Oct 2014)


Log Message:
-----------
Improve test coverage; minor typo in JIT test and other minor buglets fixed.

Modified Paths:
--------------
    code/trunk/Makefile.am
    code/trunk/RunGrepTest
    code/trunk/RunTest
    code/trunk/doc/pcre2_substring_number_from_name.3
    code/trunk/doc/pcre2api.3
    code/trunk/doc/pcre2test.1
    code/trunk/src/pcre2.h.in
    code/trunk/src/pcre2_compile.c
    code/trunk/src/pcre2_error.c
    code/trunk/src/pcre2_jit_test.c
    code/trunk/src/pcre2_substring.c
    code/trunk/src/pcre2test.c
    code/trunk/testdata/grepoutput
    code/trunk/testdata/testinput17
    code/trunk/testdata/testinput2
    code/trunk/testdata/testinput5
    code/trunk/testdata/testoutput14
    code/trunk/testdata/testoutput17
    code/trunk/testdata/testoutput2
    code/trunk/testdata/testoutput5
    code/trunk/testdata/testoutput6


Modified: code/trunk/Makefile.am
===================================================================
--- code/trunk/Makefile.am    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/Makefile.am    2014-10-31 12:34:34 UTC (rev 128)
@@ -587,11 +587,12 @@
   testdata/testoutput18 \
   testdata/testoutputEBC \
   perltest.sh
-  
+
 # RunTest and RunGrepTest should clean up after themselves, but just in case
-# they don't, add their working files to CLEANFILES. 
+# they don't, add their working files to CLEANFILES.


 CLEANFILES += \
+        testSinput \
         test3input \
         test3output \
         test3outputA \


Modified: code/trunk/RunGrepTest
===================================================================
--- code/trunk/RunGrepTest    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/RunGrepTest    2014-10-31 12:34:34 UTC (rev 128)
@@ -72,6 +72,19 @@
 ./pcre2test -C unicode >/dev/null
 utf8=$?


+# ------ Function to run and check a special pcre2grep arguments test -------
+
+checkspecial()
+  {
+  $valgrind ./pcre2grep $1 >>testtrygrep 2>&1
+  if [ $? -ne $2 ] ; then
+    echo "** pcre2grep $1 failed - check testtrygrep"
+    exit 1
+  fi
+  }
+  
+# ------ Normal tests ------ 
+
 echo "Testing pcre2grep main features"


echo "---------------------------- Test 1 ------------------------------" >testtrygrep
@@ -571,6 +584,17 @@
$cf $srcdir/testdata/grepoutputN testtrygrep
if [ $? != 0 ] ; then exit 1; fi

+
+# Finally, some tests to exercise code that is not tested above, just to be
+# sure that it runs OK. Doing this improves the coverage statistics. The output
+# is not checked.
+
+echo "Testing miscellaneous pcre2grep arguments (unchecked)"
+echo '' >testtrygrep
+checkspecial '-xxxxx' 2
+checkspecial '--help' 0
+checkspecial '--line-buffered --colour=auto abc /dev/null' 1
+
# Clean up local working files
rm -f testNinputgrep teststderrgrep testtrygrep testtemp1grep testtemp2grep


Modified: code/trunk/RunTest
===================================================================
--- code/trunk/RunTest    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/RunTest    2014-10-31 12:34:34 UTC (rev 128)
@@ -20,15 +20,10 @@
 # except test 10. Whatever order the arguments are in, the tests are always run
 # in numerical order.
 #
-# The special argument "3S" runs test 3, stopping if it fails. Test 3 is the
-# locale test, and failure usually means there's an issue with the locale
-# rather than a bug in PCRE2, so normally subsequent tests are run. "3S" is
-# useful when you want to debug or update the test.
+# Inappropriate tests are automatically skipped (with a comment to say so). For
+# example, if JIT support is not compiled, test 16 is skipped, whereas if JIT
+# support is compiled, test 15 is skipped.
 #
-# Inappropriate tests are automatically skipped (with a comment to say so): for
-# example, if JIT support is not compiled, test 12 is skipped, whereas if JIT
-# support is compiled, test 13 is skipped.
-#
 # Other arguments can be one of the words "valgrind", "valgrind-log", or "sim"
 # followed by an argument to run cross-compiled executables under a simulator,
 # for example:
@@ -48,6 +43,7 @@
 # Define test titles in variables so that they can be output as a list. Some
 # of them are modified (e.g. with -8 or -16) when used in the actual tests.


+title0="Test 0: Unchecked pcre2test argument tests (to improve coverage)"
title1="Test 1: Main non-UTF, non-UCP functionality (compatible with Perl >= 5.10)"
title2="Test 2: API, errors, internals, and non-Perl stuff"
title3="Test 3: Locale-specific features"
@@ -69,10 +65,10 @@
title16="Test 16: JIT-specific features when JIT is available"
title17="Test 17: Tests of the POSIX interface, excluding UTF/UCP"
title18="Test 18: Tests of the POSIX interface with UTF/UCP"
-
maxtest=18

if [ $# -eq 1 -a "$1" = "list" ]; then
+ echo $title0
echo $title1
echo $title2 "(not UTF or UCP)"
echo $title3
@@ -145,10 +141,22 @@
}


+# ------ Function to run and check a special pcre2test arguments test -------
+
+checkspecial()
+  {
+  $valgrind ./pcre2test $1 >>testtry
+  if [ $? -ne 0 ] ; then
+    echo "** pcre2test $1 failed - check testtry"
+    exit 1
+  fi
+  }
+
+
 # ------ Special EBCDIC Test -------


 if [ $# -eq 1 -a "$1" = "ebcdic" ]; then
-  ./pcre2test -C ebcdic >/dev/null
+  $valgrind ./pcre2test -C ebcdic >/dev/null
   ebcdic=$?
   if [ $ebcdic -ne 1 ] ; then
     echo "Cannot run EBCDIC tests: EBCDIC support not compiled"
@@ -180,6 +188,7 @@
 # Process options and select which tests to run; for those that are explicitly
 # requested, check that the necessary optional facilities are available.


+do0=no
do1=no
do2=no
do3=no
@@ -201,6 +210,7 @@

 while [ $# -gt 0 ] ; do
   case $1 in
+    0) do0=yes;;
     1) do1=yes;;
     2) do2=yes;;
     3) do3=yes;;
@@ -238,7 +248,7 @@
        tf=`expr "$1" : '\([0-9]*\)'`
        tt=`expr "$1" : '.*-\([0-9]*\)'`
        if [ "$tt" = "" ] ; then tt=$maxtest; fi
-       if expr \( "$tf" "<" 1 \) \| \( "$tt" ">" "$maxtest" \) >/dev/null; then
+       if expr \( "$tt" ">" "$maxtest" \) >/dev/null; then
          echo "Invalid test range '$1'"; exit 1
        fi
        while expr "$tf" "<=" "$tt" >/dev/null; do
@@ -287,7 +297,7 @@


 if [ "$arg8$arg16$arg32" = "" ] ; then
   if [ $support8 -ne 0 ] ; then
-    test8=
+    test8=-8
   fi
   if [ $support16 -ne 0 ] ; then
     test16=-16
@@ -296,7 +306,7 @@
     test32=-32
   fi


-# Select requested bit sizes
+# Otherwise, select requested bit sizes

 else
   if [ "$arg8" = yes ] ; then
@@ -304,7 +314,7 @@
       echo "Cannot run 8-bit library tests: 8-bit library not compiled"
       exit 1
     fi
-    test8=
+    test8=-8
   fi
   if [ "$arg16" = yes ] ; then
     if [ $support16 -eq 0 ] ; then
@@ -339,12 +349,13 @@
 # If no specific tests were requested, select all. Those that are not
 # relevant will be automatically skipped.


-if [ $do1  = no -a $do2  = no -a $do3  = no -a $do4  = no -a \
-     $do5  = no -a $do6  = no -a $do7  = no -a $do8  = no -a \
-     $do9  = no -a $do10 = no -a $do11 = no -a $do12 = no -a \
-     $do13 = no -a $do14 = no -a $do15 = no -a $do16 = no -a \
-     $do17 = no -a $do18 = no \
+if [ $do0  = no -a $do1  = no -a $do2  = no -a $do3  = no -a \
+     $do4  = no -a $do5  = no -a $do6  = no -a $do7  = no -a \
+     $do8  = no -a $do9  = no -a $do10 = no -a $do11 = no -a \
+     $do12 = no -a $do13 = no -a $do14 = no -a $do15 = no -a \
+     $do16 = no -a $do17 = no -a $do18 = no \
    ]; then
+  do0=yes
   do1=yes
   do2=yes
   do3=yes
@@ -384,310 +395,325 @@
           bits=16; echo "---- Testing 16-bit library ----"; echo "";;
     -32)  if [ "$test8$test16" != "skipskip" ] ; then echo ""; fi
           bits=32; echo "---- Testing 32-bit library ----"; echo "";;
-    *)    bits=8; echo "---- Testing 8-bit library ----"; echo "";;
+    -8)   bits=8; echo "---- Testing 8-bit library ----"; echo "";;
   esac


-# Primary non-UTF test, compatible with JIT and all versions of Perl >= 5.8
+ # Test 0 is a special test. Its output is not checked, because it will
+ # be different on different hardware and with different configurations.
+ # Running this test just exercises the code.

-if [ $do1 = yes ] ; then
-  echo $title1
-  for opt in "" $jitopt; do
-    $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput1 testtry
-    checkresult $? 1 "$opt"
-  done
-fi
+  if [ $do0 = yes ] ; then
+    echo $title0
+    echo '/abc/jit,memory' >testSinput
+    echo '   abc' >>testSinput
+    echo '' >testtry
+    checkspecial '-C'
+    checkspecial '--help'
+    checkspecial '-S 1 -t 10 testSinput'
+    echo "  OK"
+  fi


-# PCRE2 tests that are not JIT or Perl-compatible: API, errors, internals
+ # Primary non-UTF test, compatible with JIT and all versions of Perl >= 5.8

-if [ $do2 = yes ] ; then
-  echo $title2 "(excluding UTF-$bits)"
-  for opt in "" $jitopt; do
-    $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput2 testtry
-    if [ $? = 0 ] ; then
-      checkresult $? 2 "$opt"
-    else
-      echo " "
-      echo "** Test 2 requires a lot of stack. If it has crashed with a"
-      echo "** segmentation fault, it may be that you do not have enough"
-      echo "** stack available by default. Please see the 'pcre2stack' man"
-      echo "** page for a discussion of PCRE2's stack usage."
-      echo " "
-      exit 1
-    fi
-  done
-fi
+  if [ $do1 = yes ] ; then
+    echo $title1
+    for opt in "" $jitopt; do
+      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput1 testtry
+      checkresult $? 1 "$opt"
+    done
+  fi


-# Locale-specific tests, provided that either the "fr_FR" or the "french"
-# locale is available. The former is the Unix-like standard; the latter is
-# for Windows. Another possibility is "fr". Unfortunately, different versions
-# of the French locale give different outputs for some items. This test passes
-# if the output matches any one of the alternative output files.
+ # PCRE2 tests that are not JIT or Perl-compatible: API, errors, internals

-if [ $do3 = yes ] ; then
-  locale -a | grep '^fr_FR$' >/dev/null
-  if [ $? -eq 0 ] ; then
-    locale=fr_FR
-    infile=$testdata/testinput3
-    outfile=$testdata/testoutput3
-    outfile2=$testdata/testoutput3A
-    outfile3=$testdata/testoutput3B
-  else
-    infile=test3input
-    outfile=test3output
-    outfile2=test3outputA
-    outfile3=test3outputB
-    locale -a | grep '^french$' >/dev/null
+  if [ $do2 = yes ] ; then
+    echo $title2 "(excluding UTF-$bits)"
+    for opt in "" $jitopt; do
+      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput2 testtry
+      if [ $? = 0 ] ; then
+        checkresult $? 2 "$opt"
+      else
+        echo " "
+        echo "** Test 2 requires a lot of stack. If it has crashed with a"
+        echo "** segmentation fault, it may be that you do not have enough"
+        echo "** stack available by default. Please see the 'pcre2stack' man"
+        echo "** page for a discussion of PCRE2's stack usage."
+        echo " "
+        exit 1
+      fi
+    done
+  fi
+
+  # Locale-specific tests, provided that either the "fr_FR" or the "french"
+  # locale is available. The former is the Unix-like standard; the latter is
+  # for Windows. Another possibility is "fr". Unfortunately, different versions
+  # of the French locale give different outputs for some items. This test passes
+  # if the output matches any one of the alternative output files.
+
+  if [ $do3 = yes ] ; then
+    locale -a | grep '^fr_FR$' >/dev/null
     if [ $? -eq 0 ] ; then
-      locale=french
-      sed 's/fr_FR/french/' $testdata/testinput3 >test3input
-      sed 's/fr_FR/french/' $testdata/testoutput3 >test3output
-      sed 's/fr_FR/french/' $testdata/testoutput3A >test3outputA
-      sed 's/fr_FR/french/' $testdata/testoutput3B >test3outputB
+      locale=fr_FR
+      infile=$testdata/testinput3
+      outfile=$testdata/testoutput3
+      outfile2=$testdata/testoutput3A
+      outfile3=$testdata/testoutput3B
     else
-      locale -a | grep '^fr$' >/dev/null
+      infile=test3input
+      outfile=test3output
+      outfile2=test3outputA
+      outfile3=test3outputB
+      locale -a | grep '^french$' >/dev/null
       if [ $? -eq 0 ] ; then
-        locale=fr
-        sed 's/fr_FR/fr/' $testdata/intestinput3 >test3input
-        sed 's/fr_FR/fr/' $testdata/intestoutput3 >test3output
-        sed 's/fr_FR/fr/' $testdata/intestoutput3A >test3outputA
-        sed 's/fr_FR/fr/' $testdata/intestoutput3B >test3outputB
+        locale=french
+        sed 's/fr_FR/french/' $testdata/testinput3 >test3input
+        sed 's/fr_FR/french/' $testdata/testoutput3 >test3output
+        sed 's/fr_FR/french/' $testdata/testoutput3A >test3outputA
+        sed 's/fr_FR/french/' $testdata/testoutput3B >test3outputB
       else
-        locale=
+        locale -a | grep '^fr$' >/dev/null
+        if [ $? -eq 0 ] ; then
+          locale=fr
+          sed 's/fr_FR/fr/' $testdata/intestinput3 >test3input
+          sed 's/fr_FR/fr/' $testdata/intestoutput3 >test3output
+          sed 's/fr_FR/fr/' $testdata/intestoutput3A >test3outputA
+          sed 's/fr_FR/fr/' $testdata/intestoutput3B >test3outputB
+        else
+          locale=
+        fi
       fi
     fi
-  fi


-  if [ "$locale" != "" ] ; then
-    echo $title3 "(using '$locale' locale)"
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $infile testtry
-      if [ $? = 0 ] ; then
-        case "$opt" in
-          -jit) with=" with JIT";;
-          *)    with="";;
-        esac
-        if $cf $outfile testtry >teststdout || \
-           $cf $outfile2 testtry >teststdout || \
-           $cf $outfile3 testtry >teststdout
-        then
-          echo "  OK$with"
-        else
-          echo "** Locale test did not run successfully$with. The output did not match"
-          echo "   $outfile, $outfile2 or $outfile3."
-          echo "   This may mean that there is a problem with the locale settings rather"
-          echo "   than a bug in PCRE2."
-          exit 1
+    if [ "$locale" != "" ] ; then
+      echo $title3 "(using '$locale' locale)"
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $infile testtry
+        if [ $? = 0 ] ; then
+          case "$opt" in
+            -jit) with=" with JIT";;
+            *)    with="";;
+          esac
+          if $cf $outfile testtry >teststdout || \
+             $cf $outfile2 testtry >teststdout || \
+             $cf $outfile3 testtry >teststdout
+          then
+            echo "  OK$with"
+          else
+            echo "** Locale test did not run successfully$with. The output did not match"
+            echo "   $outfile, $outfile2 or $outfile3."
+            echo "   This may mean that there is a problem with the locale settings rather"
+            echo "   than a bug in PCRE2."
+            exit 1
+          fi
+        else exit 1
         fi
-      else exit 1
-      fi
-    done
-  else
-    echo "Cannot test locale-specific features - none of the 'fr_FR', 'fr' or"
-    echo "'french' locales exist, or the \"locale\" command is not available"
-    echo "to check for them."
-    echo " "
+      done
+    else
+      echo "Cannot test locale-specific features - none of the 'fr_FR', 'fr' or"
+      echo "'french' locales exist, or the \"locale\" command is not available"
+      echo "to check for them."
+      echo " "
+    fi
   fi
-fi


-# Tests for UTF and Unicode property support
+ # Tests for UTF and Unicode property support

-if [ $do4 = yes ] ; then
-  echo ${title4A}-${bits}${title4B}
-  if [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput4 testtry
-      checkresult $? 4 "$opt"
-    done
+  if [ $do4 = yes ] ; then
+    echo ${title4A}-${bits}${title4B}
+    if [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput4 testtry
+        checkresult $? 4 "$opt"
+      done
+    fi
   fi
-fi


-if [ $do5 = yes ] ; then
-  echo ${title5A}-${bits}$title5B
-  if [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput5 testtry
-      checkresult $? 5 "$opt"
-    done
+  if [ $do5 = yes ] ; then
+    echo ${title5A}-${bits}$title5B
+    if [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput5 testtry
+        checkresult $? 5 "$opt"
+      done
+    fi
   fi
-fi


-# Tests for DFA matching support
+ # Tests for DFA matching support

-if [ $do6 = yes ] ; then
-  echo $title6
-  $sim $valgrind ./pcre2test -q $bmode $testdata/testinput6 testtry
-  checkresult $? 6 ""
-fi
+  if [ $do6 = yes ] ; then
+    echo $title6
+    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput6 testtry
+    checkresult $? 6 ""
+  fi


-if [ $do7 = yes ] ; then
-  echo ${title7A}-${bits}$title7B
-  if [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput7 testtry
-    checkresult $? 7 ""
+  if [ $do7 = yes ] ; then
+    echo ${title7A}-${bits}$title7B
+    if [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput7 testtry
+      checkresult $? 7 ""
+    fi
   fi
-fi


-# Test of internal offsets and code sizes. This test is run only when there
-# is UTF/UCP support and the link size is 2. The actual tests are
-# mostly the same as in some of the above, but in this test we inspect some
-# offsets and sizes that require a known link size. This is a doublecheck for
-# the maintainer, just in case something changes unexpectely. The output from
-# this test is different in 8-bit, 16-bit, and 32-bit modes, so there are
-# mode-specific output files.
+ # Test of internal offsets and code sizes. This test is run only when there
+ # is UTF/UCP support and the link size is 2. The actual tests are
+ # mostly the same as in some of the above, but in this test we inspect some
+ # offsets and sizes that require a known link size. This is a doublecheck for
+ # the maintainer, just in case something changes unexpectely. The output from
+ # this test is different in 8-bit, 16-bit, and 32-bit modes, so there are
+ # mode-specific output files.

-if [ $do8 = yes ] ; then
-  echo $title8
-  if [ $link_size -ne 2 ] ; then
-    echo "  Skipped because link size is not 2"
-  elif [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput8 testtry
-    checkresult $? 8-$bits ""
+  if [ $do8 = yes ] ; then
+    echo $title8
+    if [ $link_size -ne 2 ] ; then
+      echo "  Skipped because link size is not 2"
+    elif [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput8 testtry
+      checkresult $? 8-$bits ""
+    fi
   fi
-fi


-# Tests for 8-bit-specific features
+ # Tests for 8-bit-specific features

-if [ "$do9" = yes ] ; then
-  echo $title9
-  if [ "$bits" = "16" -o "$bits" = "32" ] ; then
-    echo "  Skipped when running 16/32-bit tests"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput9 testtry
-      checkresult $? 9 "$opt"
-    done
+  if [ "$do9" = yes ] ; then
+    echo $title9
+    if [ "$bits" = "16" -o "$bits" = "32" ] ; then
+      echo "  Skipped when running 16/32-bit tests"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput9 testtry
+        checkresult $? 9 "$opt"
+      done
+    fi
   fi
-fi


-# Tests for UTF-8 and UCP 8-bit-specific features
+ # Tests for UTF-8 and UCP 8-bit-specific features

-if [ "$do10" = yes ] ; then
-  echo $title10
-  if [ "$bits" = "16" -o "$bits" = "32" ] ; then
-    echo "  Skipped when running 16/32-bit tests"
-  elif [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput10 testtry
-      checkresult $? 10 "$opt"
-    done
+  if [ "$do10" = yes ] ; then
+    echo $title10
+    if [ "$bits" = "16" -o "$bits" = "32" ] ; then
+      echo "  Skipped when running 16/32-bit tests"
+    elif [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput10 testtry
+        checkresult $? 10 "$opt"
+      done
+    fi
   fi
-fi


-# Tests for 16-bit and 32-bit features. Output is different for the two widths.
+ # Tests for 16-bit and 32-bit features. Output is different for the two widths.

-if [ $do11 = yes ] ; then
-  echo $title11
-  if [ "$bits" = "8" ] ; then
-    echo "  Skipped when running 8-bit tests"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput11 testtry
-      checkresult $? 11-$bits "$opt"
-    done
+  if [ $do11 = yes ] ; then
+    echo $title11
+    if [ "$bits" = "8" ] ; then
+      echo "  Skipped when running 8-bit tests"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput11 testtry
+        checkresult $? 11-$bits "$opt"
+      done
+    fi
   fi
-fi


-# Tests for 16-bit and 32-bit features with UTF-16/32 and UCP support. Output
-# is different for the two widths.
+ # Tests for 16-bit and 32-bit features with UTF-16/32 and UCP support. Output
+ # is different for the two widths.

-if [ $do12 = yes ] ; then
-  echo $title12
-  if [ "$bits" = "8" ] ; then
-    echo "  Skipped when running 8-bit tests"
-  elif [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    for opt in "" $jitopt; do
-      $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput12 testtry
-      checkresult $? 12-$bits "$opt"
-    done
+  if [ $do12 = yes ] ; then
+    echo $title12
+    if [ "$bits" = "8" ] ; then
+      echo "  Skipped when running 8-bit tests"
+    elif [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      for opt in "" $jitopt; do
+        $sim $valgrind ./pcre2test -q $bmode $opt $testdata/testinput12 testtry
+        checkresult $? 12-$bits "$opt"
+      done
+    fi
   fi
-fi


-# Tests for 16/32-bit-specific features in DFA non-UTF modes
+ # Tests for 16/32-bit-specific features in DFA non-UTF modes

-if [ $do13 = yes ] ; then
-  echo $title13
-  if [ "$bits" = "8" ] ; then
-    echo "  Skipped when running 8-bit tests"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput13 testtry
-    checkresult $? 13 ""
+  if [ $do13 = yes ] ; then
+    echo $title13
+    if [ "$bits" = "8" ] ; then
+      echo "  Skipped when running 8-bit tests"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput13 testtry
+      checkresult $? 13 ""
+    fi
   fi
-fi


-# Test non-JIT match and recursion limits
+ # Test non-JIT match and recursion limits

-if [ $do14 = yes ] ; then
-  echo $title14
-  $sim $valgrind ./pcre2test -q $bmode $testdata/testinput14 testtry
-  checkresult $? 14 ""
-fi
+  if [ $do14 = yes ] ; then
+    echo $title14
+    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput14 testtry
+    checkresult $? 14 ""
+  fi


-# Test JIT-specific features when JIT is not available
+ # Test JIT-specific features when JIT is not available

-if [ $do15 = yes ] ; then
-  echo $title15
-  if [ $jit -ne 0 ] ; then
-    echo "  Skipped because JIT is available"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput15 testtry
-    checkresult $? 15 ""
+  if [ $do15 = yes ] ; then
+    echo $title15
+    if [ $jit -ne 0 ] ; then
+      echo "  Skipped because JIT is available"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput15 testtry
+      checkresult $? 15 ""
+    fi
   fi
-fi


-# Test JIT-specific features when JIT is available
+ # Test JIT-specific features when JIT is available

-if [ $do16 = yes ] ; then
-  echo $title16
-  if [ $jit -eq 0 -o "$nojit" = "yes" ] ; then
-    echo "  Skipped because JIT is not available or not usable"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput16 testtry
-    checkresult $? 16 ""
+  if [ $do16 = yes ] ; then
+    echo $title16
+    if [ $jit -eq 0 -o "$nojit" = "yes" ] ; then
+      echo "  Skipped because JIT is not available or not usable"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput16 testtry
+      checkresult $? 16 ""
+    fi
   fi
-fi


-# Tests for the POSIX interface without UTF/UCP (8-bit only)
+ # Tests for the POSIX interface without UTF/UCP (8-bit only)

-if [ $do17 = yes ] ; then
-  echo $title17
-  if [ "$bits" = "16" -o "$bits" = "32" ] ; then
-    echo "  Skipped when running 16/32-bit tests"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput17 testtry
-    checkresult $? 17 ""
+  if [ $do17 = yes ] ; then
+    echo $title17
+    if [ "$bits" = "16" -o "$bits" = "32" ] ; then
+      echo "  Skipped when running 16/32-bit tests"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput17 testtry
+      checkresult $? 17 ""
+    fi
   fi
-fi


-# Tests for the POSIX interface with UTF/UCP (8-bit only)
+ # Tests for the POSIX interface with UTF/UCP (8-bit only)

-if [ $do18 = yes ] ; then
-  echo $title18
-  if [ "$bits" = "16" -o "$bits" = "32" ] ; then
-    echo "  Skipped when running 16/32-bit tests"
-  elif [ $utf -eq 0 ] ; then
-    echo "  Skipped because UTF-$bits support is not available"
-  else
-    $sim $valgrind ./pcre2test -q $bmode $testdata/testinput18 testtry
-    checkresult $? 18 ""
+  if [ $do18 = yes ] ; then
+    echo $title18
+    if [ "$bits" = "16" -o "$bits" = "32" ] ; then
+      echo "  Skipped when running 16/32-bit tests"
+    elif [ $utf -eq 0 ] ; then
+      echo "  Skipped because UTF-$bits support is not available"
+    else
+      $sim $valgrind ./pcre2test -q $bmode $testdata/testinput18 testtry
+      checkresult $? 18 ""
+    fi
   fi
-fi


# End of loop for 8/16/32-bit tests
done

# Clean up local working files
-rm -f test3input test3output test3outputA test3outputB teststdout testtry
+rm -f testSinput test3input test3output test3outputA test3outputB teststdout testtry

# End

Modified: code/trunk/doc/pcre2_substring_number_from_name.3
===================================================================
--- code/trunk/doc/pcre2_substring_number_from_name.3    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/doc/pcre2_substring_number_from_name.3    2014-10-31 12:34:34 UTC (rev 128)
@@ -15,16 +15,17 @@
 .rs
 .sp
 This convenience function finds the number of a named substring capturing
-parenthesis in a compiled pattern. Its arguments are:
+parenthesis in a compiled pattern, provided that it is a unique name. The 
+function arguments are:
 .sp
   \fIcode\fP    Compiled regular expression
   \fIname\fP    Name whose number is required
 .sp
 The yield of the function is the number of the parenthesis if the name is
-found, or PCRE2_ERROR_NOSUBSTRING otherwise. When duplicate names are allowed
-(PCRE2_DUPNAMES is set), it is not defined which of the numbers is returned.
-You can obtain the complete list by calling
-\fBpcre2_substring_nametable_scan()\fP.
+found, or PCRE2_ERROR_NOSUBSTRING if it is not found. When duplicate names are
+allowed (PCRE2_DUPNAMES is set), if the name is not unique,
+PCRE2_ERROR_NOUNIQUESUBSTRING is returned. You can obtain the list of numbers
+with the same name by calling \fBpcre2_substring_nametable_scan()\fP.
 .P
 There is a complete description of the PCRE2 native API in the
 .\" HREF


Modified: code/trunk/doc/pcre2api.3
===================================================================
--- code/trunk/doc/pcre2api.3    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/doc/pcre2api.3    2014-10-31 12:34:34 UTC (rev 128)
@@ -1,4 +1,4 @@
-.TH PCRE2API 3 "25 October 2014" "PCRE2 10.00"
+.TH PCRE2API 3 "29 October 2014" "PCRE2 10.00"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .sp
@@ -2332,8 +2332,9 @@
 unique (PCRE2_DUPNAMES was not set), you can find the number from the name by
 calling \fBpcre2_substring_number_from_name()\fP. The first argument is the
 compiled pattern, and the second is the name. The yield of the function is the
-subpattern number, or PCRE2_ERROR_NOSUBSTRING if there is no subpattern of that
-name.
+subpattern number, PCRE2_ERROR_NOSUBSTRING if there is no subpattern of that
+name, or PCRE2_ERROR_NOUNIQUESUBSTRING if there is more than one subpattern of 
+that name.
 .P
 Given the number, you can extract the substring directly, or use one of the
 functions described in the previous section. For convenience, there are also
@@ -2630,6 +2631,6 @@
 .rs
 .sp
 .nf
-Last updated: 25 October 2014
+Last updated: 29 October 2014
 Copyright (c) 1997-2014 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2test.1
===================================================================
--- code/trunk/doc/pcre2test.1    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/doc/pcre2test.1    2014-10-31 12:34:34 UTC (rev 128)
@@ -1,4 +1,4 @@
-.TH PCRE2TEST 1 "11 October 2014" "PCRE 10.00"
+.TH PCRE2TEST 1 "31 October 2014" "PCRE 10.00"
 .SH NAME
 pcre2test - a program for testing Perl-compatible regular expressions.
 .SH SYNOPSIS
@@ -383,6 +383,7 @@
 can add to or override default modifiers that were set by a previous
 \fB#pattern\fP command.
 .
+.
 .SS "Setting compilation options"
 .rs
 .sp
@@ -420,6 +421,7 @@
 notation. Otherwise, those less than 0x100 are output in hex without the curly
 brackets.
 .
+.
 .SS "Setting compilation controls"
 .rs
 .sp
@@ -566,6 +568,9 @@
 .sp
 The \fBparens_nest_limit\fP modifier sets a limit on the depth of nested
 parentheses in a pattern. Breaching the limit causes a compilation error.
+The default for the library is set when PCRE2 is built, but \fBpcre2test\fP 
+sets its own default of 220, which is required for running the standard test 
+suite.
 .
 .
 .SS "Using the POSIX wrapper API"
@@ -631,12 +636,13 @@
 are applied to every subject line that is processed with that pattern. They 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
+      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
+      startchar           show starting character when relevant 
 .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.
@@ -710,6 +716,7 @@
       offset=<n>                set starting offset
       ovector=<n>               set size of output vector
       recursion_limit=<n>       set a recursion limit
+      startchar                 show startchar when relevant 
 .sp
 The effects of these modifiers are described in the following sections.
 FIXME: Give more examples.
@@ -735,13 +742,28 @@
 of the actual match are indicated in the output by '<' or '>' characters
 underneath them. Here is an example:
 .sp
-  /(?<=pqr)abc(?=xyz)/
-      123pqrabcxyz456\e=allusedtext
+    re> /(?<=pqr)abc(?=xyz)/
+  data> 123pqrabcxyz456\e=allusedtext
    0: pqrabcxyz
       <<<   >>>
 .sp
 This shows that the matched string is "abc", with the preceding and following
 strings "pqr" and "xyz" also consulted during the match.
+.P
+The \fBstartchar\fP modifier requests that the starting character for the match 
+be indicated, if it is different to the start of the matched string. The only 
+time when this occurs is when \eK has been processed as part of the match. In 
+this situation, the output for the matched string is displayed from the 
+starting character instead of from the match point, with circumflex characters 
+under the earlier characters. For example:
+.sp
+    re> /abc\eKxyz/
+  data> abcxyz\e=startchar
+   0: abcxyz
+      ^^^ 
+.sp
+Unlike \fBallusedtext\fP, the \fBstartchar\fP modifier can be used with JIT.
+However, these two modifiers are mutually exclusive.
 .
 .
 .SS "Showing the value of all capture groups"
@@ -890,11 +912,13 @@
 \fB#subject\fP command. It specifies the number of pairs of offsets that are
 available for storing matching information. The default is 15.
 .P
-At least one pair of offsets is always created by
-\fBpcre2_match_data_create()\fP, for matching with PCRE2's native API, so a
-value of 0 is the same as 1. However a value of 0 is useful when testing the
-POSIX API because it causes \fBregexec()\fP to be called with a NULL capture
-vector.
+A value of zero is useful when testing the POSIX API because it causes
+\fBregexec()\fP to be called with a NULL capture vector. When not testing the
+POSIX API, a value of zero is used to cause
+\fBpcre2_match_data_create_from_pattern\fP to be called, in order to create a 
+match block of exactly the right size for the pattern. (It is not possible to 
+create a match block with a zero-length ovector; there is always one pair of 
+offsets.)
 .
 .
 .SH "THE ALTERNATIVE MATCHING FUNCTION"
@@ -1159,6 +1183,6 @@
 .rs
 .sp
 .nf
-Last updated: 11 October 2014
+Last updated: 31 October 2014
 Copyright (c) 1997-2014 University of Cambridge.
 .fi


Modified: code/trunk/src/pcre2.h.in
===================================================================
--- code/trunk/src/pcre2.h.in    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2.h.in    2014-10-31 12:34:34 UTC (rev 128)
@@ -196,29 +196,30 @@
 /* Error codes for pcre2[_dfa]_match(), substring extraction functions, and
 context functions. */


-#define PCRE2_ERROR_BADDATA         (-29)
-#define PCRE2_ERROR_BADLENGTH       (-30)
-#define PCRE2_ERROR_BADMAGIC        (-31)
-#define PCRE2_ERROR_BADMODE         (-32)
-#define PCRE2_ERROR_BADOFFSET       (-33)
-#define PCRE2_ERROR_BADOPTION       (-34)
-#define PCRE2_ERROR_BADUTFOFFSET    (-35)
-#define PCRE2_ERROR_CALLOUT         (-36)  /* Never used by PCRE2 itself */
-#define PCRE2_ERROR_DFA_BADRESTART  (-37)
-#define PCRE2_ERROR_DFA_RECURSE     (-38)
-#define PCRE2_ERROR_DFA_UCOND       (-39)
-#define PCRE2_ERROR_DFA_UITEM       (-40)
-#define PCRE2_ERROR_DFA_WSSIZE      (-41)
-#define PCRE2_ERROR_INTERNAL        (-42)
-#define PCRE2_ERROR_JIT_BADOPTION   (-43)
-#define PCRE2_ERROR_JIT_STACKLIMIT  (-44)
-#define PCRE2_ERROR_MATCHLIMIT      (-45)
-#define PCRE2_ERROR_NOMEMORY        (-46)
-#define PCRE2_ERROR_NOSUBSTRING     (-47)
-#define PCRE2_ERROR_NULL            (-48)
-#define PCRE2_ERROR_RECURSELOOP     (-49)
-#define PCRE2_ERROR_RECURSIONLIMIT  (-50)
-#define PCRE2_ERROR_UNSET           (-51)
+#define PCRE2_ERROR_BADDATA           (-29)
+#define PCRE2_ERROR_BADLENGTH         (-30)
+#define PCRE2_ERROR_BADMAGIC          (-31)
+#define PCRE2_ERROR_BADMODE           (-32)
+#define PCRE2_ERROR_BADOFFSET         (-33)
+#define PCRE2_ERROR_BADOPTION         (-34)
+#define PCRE2_ERROR_BADUTFOFFSET      (-35)
+#define PCRE2_ERROR_CALLOUT           (-36)  /* Never used by PCRE2 itself */
+#define PCRE2_ERROR_DFA_BADRESTART    (-37)
+#define PCRE2_ERROR_DFA_RECURSE       (-38)
+#define PCRE2_ERROR_DFA_UCOND         (-39)
+#define PCRE2_ERROR_DFA_UITEM         (-40)
+#define PCRE2_ERROR_DFA_WSSIZE        (-41)
+#define PCRE2_ERROR_INTERNAL          (-42)
+#define PCRE2_ERROR_JIT_BADOPTION     (-43)
+#define PCRE2_ERROR_JIT_STACKLIMIT    (-44)
+#define PCRE2_ERROR_MATCHLIMIT        (-45)
+#define PCRE2_ERROR_NOMEMORY          (-46)
+#define PCRE2_ERROR_NOSUBSTRING       (-47)
+#define PCRE2_ERROR_NOUNIQUESUBSTRING (-48)
+#define PCRE2_ERROR_NULL              (-49)
+#define PCRE2_ERROR_RECURSELOOP       (-50)
+#define PCRE2_ERROR_RECURSIONLIMIT    (-51)
+#define PCRE2_ERROR_UNSET             (-52)


/* Request types for pcre2_pattern_info() */


Modified: code/trunk/src/pcre2_compile.c
===================================================================
--- code/trunk/src/pcre2_compile.c    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2_compile.c    2014-10-31 12:34:34 UTC (rev 128)
@@ -6068,7 +6068,7 @@
     /* Process nested bracketed regex. First check for parentheses nested too
     deeply. */


-    if ((cb->parens_depth += 1) > PARENS_NEST_LIMIT)
+    if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit))
       {
       *errorcodeptr = ERR19;
       goto FAILED;
@@ -7786,7 +7786,7 @@
 NULL to indicate that forward references have been filled in. */


 if (cb.workspace_size > COMPILE_WORK_SIZE)
-  ccontext->memctl.free((void *)cb.start_workspace,
+  ccontext->memctl.free((void *)cb.start_workspace, 
     ccontext->memctl.memory_data);
 cb.start_workspace = NULL;



Modified: code/trunk/src/pcre2_error.c
===================================================================
--- code/trunk/src/pcre2_error.c    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2_error.c    2014-10-31 12:34:34 UTC (rev 128)
@@ -221,9 +221,10 @@
   "match limit exceeded\0"
   "no more memory\0"
   "unknown or unset substring\0"
+  "non-unique substring name\0" 
   "NULL argument passed\0"
+  /* 50 */
   "nested recursion at the same subject position\0"
-  /* 50 */
   "recursion limit exceeded\0"
   "requested value is not set\0"
   ;


Modified: code/trunk/src/pcre2_jit_test.c
===================================================================
--- code/trunk/src/pcre2_jit_test.c    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2_jit_test.c    2014-10-31 12:34:34 UTC (rev 128)
@@ -1127,7 +1127,7 @@
 #elif defined SUPPORT_PCRE2_16
     pcre2_config_16(PCRE2_CONFIG_JITTARGET, &cpu_info);
 #elif defined SUPPORT_PCRE2_32
-    pcre2_config_32(PCRE2_CONFIG_JITTARGET, &cpu_info));
+    pcre2_config_32(PCRE2_CONFIG_JITTARGET, &cpu_info);
 #endif


     printf("Running JIT regression tests\n");


Modified: code/trunk/src/pcre2_substring.c
===================================================================
--- code/trunk/src/pcre2_substring.c    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2_substring.c    2014-10-31 12:34:34 UTC (rev 128)
@@ -409,7 +409,8 @@
   firstptr    where to put the pointer to the first entry
   lastptr     where to put the pointer to the last entry


-Returns:      if firstptr and lastptr are NULL, a group number;
+Returns:      if firstptr and lastptr are NULL, a group number for a
+                unique substring, or PCRE2_ERROR_NOUNIQUESUBSTRING
               otherwise, the length of each entry, or a negative number
                 (PCRE2_ERROR_NOSUBSTRING) if not found
 */
@@ -433,7 +434,6 @@
     PCRE2_SPTR first;
     PCRE2_SPTR last;
     PCRE2_SPTR lastentry;
-    if (firstptr == NULL) return GET2(entry, 0);
     lastentry = nametable + entrysize * (code->name_count - 1);
     first = last = entry;
     while (first > nametable)
@@ -446,6 +446,8 @@
       if (PRIV(strcmp)(stringname, (last + entrysize + IMM2_SIZE)) != 0) break;
       last += entrysize;
       }
+    if (firstptr == NULL) 
+      return (first == last)? (int)GET2(entry, 0) : PCRE2_ERROR_NOUNIQUESUBSTRING;
     *firstptr = first;
     *lastptr = last;
     return entrysize;


Modified: code/trunk/src/pcre2test.c
===================================================================
--- code/trunk/src/pcre2test.c    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/src/pcre2test.c    2014-10-31 12:34:34 UTC (rev 128)
@@ -319,29 +319,30 @@
 /* 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. */


-#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_NONE     0x00000080u
-#define CTL_DFA              0x00000100u
-#define CTL_FINDLIMITS       0x00000200u
-#define CTL_FULLBINCODE      0x00000400u
-#define CTL_GETALL           0x00000800u
-#define CTL_GLOBAL           0x00001000u
-#define CTL_HEXPAT           0x00002000u
-#define CTL_INFO             0x00004000u
-#define CTL_JITVERIFY        0x00008000u
-#define CTL_MARK             0x00010000u
-#define CTL_MEMORY           0x00020000u
-#define CTL_PATLEN           0x00040000u
-#define CTL_POSIX            0x00080000u
+#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_NONE       0x00000080u
+#define CTL_DFA                0x00000100u
+#define CTL_FINDLIMITS         0x00000200u
+#define CTL_FULLBINCODE        0x00000400u
+#define CTL_GETALL             0x00000800u
+#define CTL_GLOBAL             0x00001000u
+#define CTL_HEXPAT             0x00002000u
+#define CTL_INFO               0x00004000u
+#define CTL_JITVERIFY          0x00008000u
+#define CTL_MARK               0x00010000u
+#define CTL_MEMORY             0x00020000u
+#define CTL_PATLEN             0x00040000u
+#define CTL_POSIX              0x00080000u
+#define CTL_STARTCHAR          0x00100000u


-#define CTL_BSR_SET          0x00100000u  /* This is informational */
-#define CTL_NL_SET           0x00200000u  /* This is informational */
+#define CTL_BSR_SET          0x80000000u  /* This is informational */
+#define CTL_NL_SET           0x40000000u  /* This is informational */


 #define CTL_DEBUG            (CTL_FULLBINCODE|CTL_INFO)  /* For setting */
 #define CTL_ANYINFO          (CTL_DEBUG|CTL_BINCODE)     /* For testing */
@@ -358,7 +359,8 @@
                     CTL_GLOBAL|\
                     CTL_JITVERIFY|\
                     CTL_MARK|\
-                    CTL_MEMORY)
+                    CTL_MEMORY|\
+                    CTL_STARTCHAR)


 typedef struct patctl {    /* Structure for pattern modifiers. */
   uint32_t  options;       /* Must be in same position as datctl */
@@ -476,6 +478,7 @@
   { "ps",                  MOD_DAT,  MOD_OPT, PCRE2_PARTIAL_SOFT,        DO(options) },
   { "recursion_limit",     MOD_CTM,  MOD_INT, 0,                         MO(recursion_limit) },
   { "stackguard",          MOD_PAT,  MOD_INT, 0,                         PO(stackguard_test) },
+  { "startchar",           MOD_PND,  MOD_CTL, CTL_STARTCHAR,             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) },
@@ -499,6 +502,10 @@


#define POSIX_SUPPORTED_MATCH_CONTROLS (CTL_AFTERTEXT|CTL_ALLAFTERTEXT)

+/* Controls that are mutually exclusive. */
+
+#define EXCLUSIVE_DAT_CONTROLS (CTL_ALLUSEDTEXT|CTL_STARTCHAR)
+
/* Table of single-character abbreviated modifiers. The index field is
initialized to -1, but the first time the modifier is encountered, it is filled
in with the index of the full entry in modlist, to save repeated searching when
@@ -654,7 +661,7 @@

 #ifdef SUPPORT_PCRE2_8
 static pcre2_code_8             *compiled_code8;
-static pcre2_general_context_8  *general_context8;
+static pcre2_general_context_8  *general_context8, *general_context_copy8;
 static pcre2_compile_context_8  *pat_context8, *default_pat_context8;
 static pcre2_match_context_8    *dat_context8, *default_dat_context8;
 static pcre2_match_data_8       *match_data8;
@@ -662,7 +669,7 @@


 #ifdef SUPPORT_PCRE2_16
 static pcre2_code_16            *compiled_code16;
-static pcre2_general_context_16 *general_context16;
+static pcre2_general_context_16 *general_context16, *general_context_copy16;
 static pcre2_compile_context_16 *pat_context16, *default_pat_context16;
 static pcre2_match_context_16   *dat_context16, *default_dat_context16;
 static pcre2_match_data_16      *match_data16;
@@ -672,7 +679,7 @@


 #ifdef SUPPORT_PCRE2_32
 static pcre2_code_32            *compiled_code32;
-static pcre2_general_context_32 *general_context32;
+static pcre2_general_context_32 *general_context32, *general_context_copy32;
 static pcre2_compile_context_32 *pat_context32, *default_pat_context32;
 static pcre2_match_context_32   *dat_context32, *default_dat_context32;
 static pcre2_match_data_32      *match_data32;
@@ -771,11 +778,32 @@
   else \
     r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size))


+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_get_ovector_count_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_get_ovector_count_16(G(b,16)); \
+  else \
+    a = pcre2_get_ovector_count_32(G(b,32))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_get_startchar_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_get_startchar_16(G(b,16)); \
+  else \
+    a = pcre2_get_startchar_32(G(b,32))
+
 #define PCRE2_JIT_COMPILE(a,b) \
   if (test_mode == PCRE8_MODE) pcre2_jit_compile_8(G(a,8),b); \
   else if (test_mode == PCRE16_MODE) pcre2_jit_compile_16(G(a,16),b); \
   else pcre2_jit_compile_32(G(a,32),b)


+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+  if (test_mode == PCRE8_MODE) pcre2_jit_free_unused_memory_8(G(a,8)); \
+  else if (test_mode == PCRE16_MODE) pcre2_jit_free_unused_memory_16(G(a,16)); \
+  else pcre2_jit_free_unused_memory_32(G(a,32))
+
 #define PCRE2_JIT_STACK_ALLOC(a,b,c,d) \
   if (test_mode == PCRE8_MODE) \
     a = (PCRE2_JIT_STACK *)pcre2_jit_stack_alloc_8(b,c,d); \
@@ -821,6 +849,14 @@
   else \
     G(a,32) = pcre2_match_data_create_32(b,c)


+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c); \
+  else if (test_mode == PCRE16_MODE) \
+    G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c); \
+  else \
+    G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
+
 #define PCRE2_MATCH_DATA_FREE(a) \
   if (test_mode == PCRE8_MODE) \
     pcre2_match_data_free_8(G(a,8)); \
@@ -877,6 +913,14 @@
   else \
     pcre2_set_match_limit_32(G(a,32),b)


+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_parens_nest_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_parens_nest_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_parens_nest_limit_32(G(a,32),b)
+
 #define PCRE2_SET_RECURSION_LIMIT(a,b) \
   if (test_mode == PCRE8_MODE) \
     pcre2_set_recursion_limit_8(G(a,8),b); \
@@ -923,6 +967,22 @@
   else \
     a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)


+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d); \
+  else \
+    a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_length_bynumber_8(G(b,8),c,d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_length_bynumber_16(G(b,16),c,d); \
+  else \
+    a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
+
 #define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
   if (test_mode == PCRE8_MODE) \
     a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d); \
@@ -939,6 +999,14 @@
   else \
     pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)


+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_number_from_name_8(G(b,8),G(c,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_number_from_name_16(G(b,16),G(c,16)); \
+  else \
+    a = pcre2_substring_number_from_name_32(G(b,32),G(c,32))
+
 #define PTR(x) ( \
   (test_mode == PCRE8_MODE)? (void *)G(x,8) : \
   (test_mode == PCRE16_MODE)? (void *)G(x,16) : \
@@ -1082,12 +1150,30 @@
   else \
     r = G(pcre2_get_error_message_,BITTWO)(a,G(b,BITTWO),G(G(b,BITTWO),_size))


+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_get_ovector_count_,BITONE)(G(b,BITONE)); \
+  else \
+    a = G(pcre2_get_ovector_count_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_get_startchar_,BITONE)(G(b,BITONE)); \
+  else \
+    a = G(pcre2_get_startchar_,BITTWO)(G(b,BITTWO))
+
 #define PCRE2_JIT_COMPILE(a,b) \
   if (test_mode == G(G(PCRE,BITONE),_MODE)) \
     G(pcre2_jit_compile_,BITONE)(G(a,BITONE),b); \
   else \
     G(pcre2_jit_compile_,BITTWO)(G(a,BITTWO),b)


+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_jit_free_unused_memory_,BITONE)(G(a,BITONE)); \
+  else \
+    G(pcre2_jit_free_unused_memory_,BITTWO)(G(a,BITTWO))
+
 #define PCRE2_JIT_STACK_ALLOC(a,b,c,d) \
   if (test_mode == G(G(PCRE,BITONE),_MODE)) \
     a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_alloc_,BITONE)(b,c,d); \
@@ -1126,6 +1212,12 @@
   else \
     G(a,BITTWO) = G(pcre2_match_data_create_,BITTWO)(b,c)


+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE) = G(pcre2_match_data_create_from_pattern_,BITONE)(G(b,BITONE),c); \
+  else \
+    G(a,BITTWO) = G(pcre2_match_data_create_from_pattern_,BITTWO)(G(b,BITTWO),c)
+
 #define PCRE2_MATCH_DATA_FREE(a) \
   if (test_mode == G(G(PCRE,BITONE),_MODE)) \
     G(pcre2_match_data_free_,BITONE)(G(a,BITONE)); \
@@ -1170,6 +1262,12 @@
   else \
     G(pcre2_set_match_limit_,BITTWO)(G(a,BITTWO),b)


+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_parens_nest_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_parens_nest_limit_,BITTWO)(G(a,BITTWO),b)
+
 #define PCRE2_SET_RECURSION_LIMIT(a,b) \
   if (test_mode == G(G(PCRE,BITONE),_MODE)) \
     G(pcre2_set_recursion_limit_,BITONE)(G(a,BITONE),b); \
@@ -1213,6 +1311,18 @@
     a = G(pcre2_substring_get_bynumber_,BITTWO)(G(b,BITTWO),c,\
       (G(PCRE2_UCHAR,BITTWO) **)d,e)


+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_length_byname_,BITONE)(G(b,BITONE),G(c,BITONE),d); \
+  else \
+    a = G(pcre2_substring_length_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_length_bynumber_,BITONE)(G(b,BITONE),c,d); \
+  else \
+    a = G(pcre2_substring_length_bynumber_,BITTWO)(G(b,BITTWO),c,d)
+
 #define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
   if (test_mode == G(G(PCRE,BITONE),_MODE)) \
     a = G(pcre2_substring_list_get_,BITONE)(G(b,BITONE), \
@@ -1227,6 +1337,12 @@
   else \
     G(pcre2_substring_list_free_,BITTWO)((G(PCRE2_SPTR,BITTWO) *)a)


+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_number_from_name_,BITONE)(G(b,BITONE),G(c,BITONE)); \
+  else \
+    a = G(pcre2_substring_number_from_name_,BITTWO)(G(b,BITTWO),G(c,BITTWO))
+
 #define PTR(x) ( \
   (test_mode == G(G(PCRE,BITONE),_MODE))? (void *)G(x,BITONE) : \
   (void *)G(x,BITTWO))
@@ -1298,7 +1414,10 @@
   a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8),i,j)
 #define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
   r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_8(G(b,8))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_8(G(b,8))
 #define PCRE2_JIT_COMPILE(a,b) pcre2_jit_compile_8(G(a,8),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_8(G(a,8))
 #define PCRE2_JIT_STACK_ALLOC(a,b,c,d) \
   a = (PCRE2_JIT_STACK *)pcre2_jit_stack_alloc_8(b,c,d);
 #define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
@@ -1308,6 +1427,8 @@
 #define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
   a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8))
 #define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,8) = pcre2_match_data_create_8(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c)
 #define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_8(G(a,8))
 #define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_8(G(b,8),c,d)
 #define PCRE2_PRINTINT(a) pcre2_printint_8(compiled_code8,outfile,a)
@@ -1317,6 +1438,7 @@
 #define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b) \
   pcre2_set_compile_recursion_guard_8(G(a,8),b)
 #define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_8(G(a,8),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_8(G(a,8),b)
 #define PCRE2_SET_RECURSION_LIMIT(a,b) pcre2_set_recursion_limit_8(G(a,8),b)
 #define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
   a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e)
@@ -1327,10 +1449,16 @@
   a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e)
 #define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
   a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_8(G(b,8),c,d)
 #define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
   a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d)
 #define PCRE2_SUBSTRING_LIST_FREE(a) \
   pcre2_substring_list_free_8((PCRE2_SPTR8 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_8(G(b,8),G(c,8));
 #define PTR(x) (void *)G(x,8)
 #define SETFLD(x,y,z) G(x,8)->y = z
 #define SETFLDVEC(x,y,v,z) G(x,8)->y[v] = z
@@ -1362,7 +1490,10 @@
   a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16),i,j)
 #define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
   r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_16(G(b,16))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_16(G(b,16))
 #define PCRE2_JIT_COMPILE(a,b) pcre2_jit_compile_16(G(a,16),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_16(G(a,16))
 #define PCRE2_JIT_STACK_ALLOC(a,b,c,d) \
   a = (PCRE2_JIT_STACK *)pcre2_jit_stack_alloc_16(b,c,d);
 #define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
@@ -1372,6 +1503,8 @@
 #define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
   a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16))
 #define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,16) = pcre2_match_data_create_16(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c)
 #define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_16(G(a,16))
 #define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_16(G(b,16),c,d)
 #define PCRE2_PRINTINT(a) pcre2_printint_16(compiled_code16,outfile,a)
@@ -1381,6 +1514,7 @@
 #define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b) \
   pcre2_set_compile_recursion_guard_16(G(a,16),b)
 #define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_16(G(a,16),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_16(G(a,16),b)
 #define PCRE2_SET_RECURSION_LIMIT(a,b) pcre2_set_recursion_limit_16(G(a,16),b)
 #define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
   a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e)
@@ -1391,10 +1525,16 @@
   a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e)
 #define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
   a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_16(G(b,16),c,d)
 #define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
   a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d)
 #define PCRE2_SUBSTRING_LIST_FREE(a) \
   pcre2_substring_list_free_16((PCRE2_SPTR16 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_16(G(b,16),G(c,16));
 #define PTR(x) (void *)G(x,16)
 #define SETFLD(x,y,z) G(x,16)->y = z
 #define SETFLDVEC(x,y,v,z) G(x,16)->y[v] = z
@@ -1426,7 +1566,10 @@
   a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32),i,j)
 #define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
   r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_32(G(b,32))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_32(G(b,32))
 #define PCRE2_JIT_COMPILE(a,b) pcre2_jit_compile_32(G(a,32),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_32(G(a,32))
 #define PCRE2_JIT_STACK_ALLOC(a,b,c,d) \
   a = (PCRE2_JIT_STACK *)pcre2_jit_stack_alloc_32(b,c,d);
 #define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
@@ -1436,6 +1579,8 @@
 #define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
   a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32))
 #define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,32) = pcre2_match_data_create_32(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
 #define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_32(G(a,32))
 #define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_32(G(b,32),c,d)
 #define PCRE2_PRINTINT(a) pcre2_printint_32(compiled_code32,outfile,a)
@@ -1445,6 +1590,7 @@
 #define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b) \
   pcre2_set_compile_recursion_guard_32(G(a,32),b)
 #define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_32(G(a,32),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_32(G(a,32),b)
 #define PCRE2_SET_RECURSION_LIMIT(a,b) pcre2_set_recursion_limit_32(G(a,32),b)
 #define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
   a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e)
@@ -1455,10 +1601,16 @@
   a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e)
 #define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
   a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
 #define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
   a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d)
 #define PCRE2_SUBSTRING_LIST_FREE(a) \
   pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_32(G(b,32),G(c,32));
 #define PTR(x) (void *)G(x,32)
 #define SETFLD(x,y,z) G(x,32)->y = z
 #define SETFLDVEC(x,y,v,z) G(x,32)->y[v] = z
@@ -2978,43 +3130,48 @@




-#ifdef SUPPORT_PCRE2_8
 /*************************************************
-*                Show compile controls           *
+*                Show control bits               *
 *************************************************/


-/* Called for unsupported POSIX modifiers, and therefore needed only when the
-8-bit library is supported.
+/* Called for mutually exclusive controls and for unsupported POSIX controls.
+Because the bits are unique, this can be used for both pattern and data control
+words.

 Arguments:
   controls    control bits
   before      text to print before
-  after       text to print after


 Returns:      nothing
 */


static void
-show_compile_controls(uint32_t controls, const char *before, const char *after)
+show_controls(uint32_t controls, const char *before)
{
-fprintf(outfile, "%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",
before,
((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "",
((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "",
((controls & CTL_ALLCAPTURES) != 0)? " allcaptures" : "",
+ ((controls & CTL_ALLUSEDTEXT) != 0)? " allusedtext" : "",
((controls & CTL_ALTGLOBAL) != 0)? " altglobal" : "",
((controls & CTL_BINCODE) != 0)? " bincode" : "",
+ ((controls & CTL_CALLOUT_CAPTURE) != 0)? " callout_capture" : "",
+ ((controls & CTL_CALLOUT_NONE) != 0)? " callout_none" : "",
+ ((controls & CTL_DFA) != 0)? " dfa" : "",
+ ((controls & CTL_FINDLIMITS) != 0)? " find_limits" : "",
((controls & CTL_FULLBINCODE) != 0)? " fullbincode" : "",
+ ((controls & CTL_GETALL) != 0)? " getall" : "",
((controls & CTL_GLOBAL) != 0)? " global" : "",
((controls & CTL_HEXPAT) != 0)? " hex" : "",
((controls & CTL_INFO) != 0)? " info" : "",
((controls & CTL_JITVERIFY) != 0)? " jitverify" : "",
((controls & CTL_MARK) != 0)? " mark" : "",
+ ((controls & CTL_MEMORY) != 0)? " memory" : "",
((controls & CTL_PATLEN) != 0)? " use_length" : "",
((controls & CTL_POSIX) != 0)? " posix" : "",
- after);
+ ((controls & CTL_STARTCHAR) != 0)? " startchar" : "");
}
-#endif /* SUPPORT_PCRE2_8 */



@@ -3066,34 +3223,6 @@

 #ifdef SUPPORT_PCRE2_8
 /*************************************************
-*                Show match controls           *
-*************************************************/
-
-/* Called for unsupported POSIX modifiers. */
-
-static void
-show_match_controls(uint32_t controls)
-{
-fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
-  ((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "",
-  ((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "",
-  ((controls & CTL_ALLCAPTURES) != 0)? " allcaptures" : "",
-  ((controls & CTL_ALTGLOBAL) != 0)? " altglobal" : "",
-  ((controls & CTL_CALLOUT_CAPTURE) != 0)? " callout_capture" : "",
-  ((controls & CTL_CALLOUT_NONE) != 0)? " callout_none" : "",
-  ((controls & CTL_DFA) != 0)? " dfa" : "",
-  ((controls & CTL_FINDLIMITS) != 0)? " find_limits" : "",
-  ((controls & CTL_GETALL) != 0)? " getall" : "",
-  ((controls & CTL_GLOBAL) != 0)? " global" : "",
-  ((controls & CTL_JITVERIFY) != 0)? " jitverify" : "",
-  ((controls & CTL_MARK) != 0)? " mark" : "",
-  ((controls & CTL_MEMORY) != 0)? " memory" : "");
-}
-#endif  /* SUPPORT_PCRE2_8 */
-
-
-#ifdef SUPPORT_PCRE2_8
-/*************************************************
 *                Show match options              *
 *************************************************/


@@ -3635,8 +3764,7 @@
     }
   if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0)
     {
-    show_compile_controls(
-      pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS, msg, "");
+    show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS, msg);
     msg = "";
     }


@@ -4345,6 +4473,16 @@
if (p[-1] != 0 && !decode_modifiers(p, CTX_DAT, NULL, &dat_datctl))
return PR_OK;

+/* Check for mutually exclusive modifiers. */
+
+c = dat_datctl.control & EXCLUSIVE_DAT_CONTROLS;
+if (c - (c & -c) != 0)
+  {
+  show_controls(c, "** Not allowed together:");
+  fprintf(outfile, "\n");
+  return PR_OK;
+  }
+
 /* Now run the pattern match: len contains the byte length, ulen contains the
 code unit length, and pp points to the subject string. POSIX matching is only
 possible in 8-bit mode, and it does not support timing or other fancy features.
@@ -4375,8 +4513,7 @@
     }
   if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0)
     {
-    fprintf(outfile, "%s", msg);
-    show_match_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS);
+    show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS, msg);
     msg = "";
     }


@@ -4445,11 +4582,6 @@
dat_datctl.control &= ~CTL_ALLUSEDTEXT;
}

-/* As pcre2_match_data_create() imposes a minimum of 1 on the ovector count, we
-must do so too. */
-
-if (dat_datctl.oveccount < 1) dat_datctl.oveccount = 1;
-
/* Enable display of malloc/free if wanted. */

 show_memory = (dat_datctl.control & CTL_MEMORY) != 0;
@@ -4485,10 +4617,17 @@
    PCRE2_JIT_STACK_ASSIGN(compiled_code, jit_callback, NULL);
    }


-/* Adjust match_data according to size of offsets required. */
+/* Adjust match_data according to size of offsets required. A size of zero
+causes a new match data block to be obtained that exactly fits the pattern. */

-if (dat_datctl.oveccount <= max_oveccount)
+if (dat_datctl.oveccount == 0)
   {
+  PCRE2_MATCH_DATA_FREE(match_data);
+  PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(match_data, compiled_code, NULL);
+  PCRE2_GET_OVECTOR_COUNT(max_oveccount, match_data);
+  }
+else if (dat_datctl.oveccount <= max_oveccount)
+  {
   SETFLD(match_data, oveccount, dat_datctl.oveccount);
   }
 else
@@ -4619,16 +4758,18 @@
   if (capcount >= 0)
     {
     int i;
+    uint32_t oveccount;
     uint8_t *nptr;


     /* This is a check against a lunatic return value. */


-    if (capcount > (int)dat_datctl.oveccount)
+    PCRE2_GET_OVECTOR_COUNT(oveccount, match_data);
+    if (capcount > (int)oveccount)
       {
       fprintf(outfile,
         "** PCRE2 error: returned count %d is too big for ovector count %d\n",
-        capcount, dat_datctl.oveccount);
-      capcount = dat_datctl.oveccount;
+        capcount, oveccount);
+      capcount = oveccount;
       if ((dat_datctl.control & CTL_ANYGLOB) != 0)
         {
         fprintf(outfile, "** Global loop abandoned\n");
@@ -4638,9 +4779,8 @@


     /* If this is not the first time round a global loop, check that the
     returned string has changed. If not, there is a bug somewhere and we must
-    break the loop because it will go on for ever. We know that for a global
-    match there must be at least two elements in the ovector. This is checked
-    above. */
+    break the loop because it will go on for ever. We know that there are
+    always at least two elements in the ovector. */


     if (gmatched > 0 && ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
       {
@@ -4660,7 +4800,7 @@
       if (pattern_info(PCRE2_INFO_CAPTURECOUNT, &maxcapcount, FALSE) < 0)
         return PR_SKIP;
       capcount = maxcapcount + 1;   /* Allow for full match */
-      if (capcount > (int)dat_datctl.oveccount) capcount = dat_datctl.oveccount;
+      if (capcount > (int)oveccount) capcount = oveccount;
       }


     /* Output the captured substrings. Note that, for the matched string,
@@ -4710,25 +4850,45 @@


         if (showallused)
           {
+          PCRE2_SIZE j;
           PCHARS(lleft, pp, leftchar, start - leftchar, utf, outfile);
           PCHARS(lmiddle, pp, start, end - start, utf, outfile);
           PCHARS(lright, pp, end, rightchar - end, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
+          fprintf(outfile, "\n    ");
+          for (j = 0; j < lleft; j++) fprintf(outfile, "<");
+          for (j = 0; j < lmiddle; j++) fprintf(outfile, " ");
+          for (j = 0; j < lright; j++) fprintf(outfile, ">");
           }
-        else
+
+        /* When a pattern contains \K, the start of match position may be
+        different to the start of the matched string. When this is the case,
+        show it when requested. */
+
+        else if ((dat_datctl.control & CTL_STARTCHAR) != 0)
           {
+          PCRE2_SIZE startchar;
+          PCRE2_GET_STARTCHAR(startchar, match_data);
+          PCHARS(lleft, pp, startchar, start - startchar, utf, outfile);
           PCHARSV(pp, start, end - start, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
+          if (startchar != start)
+            {
+            PCRE2_SIZE j;
+            fprintf(outfile, "\n    ");
+            for (j = 0; j < lleft; j++) fprintf(outfile, "^");
+            }
           }


-        if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
-          fprintf(outfile, " (JIT)");
+        /* Otherwise, just show the matched string. */


-        if (showallused)
+        else
           {
-          PCRE2_SIZE j;
-          fprintf(outfile, "\n    ");
-          for (j = 0; j < lleft; j++) fprintf(outfile, "<");
-          for (j = 0; j < lmiddle; j++) fprintf(outfile, " ");
-          for (j = 0; j < lright; j++) fprintf(outfile, ">");
+          PCHARSV(pp, start, end - start, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
           }
         }


@@ -4768,20 +4928,33 @@
     for (i = 0; i < MAXCPYGET && dat_datctl.copy_numbers[i] >= 0; i++)
       {
       int rc;
-      PCRE2_SIZE length;
+      PCRE2_SIZE length, length2;
       uint32_t copybuffer[256];
       uint32_t n = (uint32_t)(dat_datctl.copy_numbers[i]);
       length = sizeof(copybuffer)/code_unit_size;
       PCRE2_SUBSTRING_COPY_BYNUMBER(rc, match_data, n, copybuffer, &length);
       if (rc < 0)
         {
-        fprintf(outfile, "copy substring %d failed (%d): ", n, rc);
+        fprintf(outfile, "Copy substring %d failed (%d): ", n, rc);
         PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
         PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
         fprintf(outfile, "\n");
         }
       else
         {
+        PCRE2_SUBSTRING_LENGTH_BYNUMBER(rc, match_data, n, &length2);
+        if (rc < 0)
+          {
+          fprintf(outfile, "Get substring %d length failed (%d): ", n, rc);
+          PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
+          PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
+          fprintf(outfile, "\n");
+          }
+        else if (length2 != length)
+          {
+          fprintf(outfile, "Mismatched substring lengths: %ld %ld\n",
+            length, length2);
+          }
         fprintf(outfile, "%2dC ", n);
         PCHARSV(copybuffer, 0, length, utf, outfile);
         fprintf(outfile, " (%lu)\n", (unsigned long)length);
@@ -4794,7 +4967,8 @@
     for (;;)
       {
       int rc;
-      PCRE2_SIZE length;
+      int groupnumber;
+      PCRE2_SIZE length, length2;
       uint32_t copybuffer[256];
       int namelen = strlen((const char *)nptr);
 #if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
@@ -4812,20 +4986,39 @@
       if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
 #endif


+      PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+      if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+        fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
       length = sizeof(copybuffer)/code_unit_size;
       PCRE2_SUBSTRING_COPY_BYNAME(rc, match_data, pbuffer, copybuffer, &length);
       if (rc < 0)
         {
-        fprintf(outfile, "copy substring '%s' failed (%d): ", nptr, rc);
+        fprintf(outfile, "Copy substring '%s' failed (%d): ", nptr, rc);
         PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
         PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
         fprintf(outfile, "\n");
         }
       else
         {
+        PCRE2_SUBSTRING_LENGTH_BYNAME(rc, match_data, pbuffer, &length2);
+        if (rc < 0)
+          {
+          fprintf(outfile, "Get substring '%s' length failed (%d): ", nptr, rc);
+          PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
+          PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
+          fprintf(outfile, "\n");
+          }
+        else if (length2 != length)
+          {
+          fprintf(outfile, "Mismatched substring lengths: %ld %ld\n",
+            length, length2);
+          }
         fprintf(outfile, "  C ");
         PCHARSV(copybuffer, 0, length, utf, outfile);
-        fprintf(outfile, " (%lu) %s\n", (unsigned long)length, nptr);
+        fprintf(outfile, " (%lu) %s", (unsigned long)length, nptr);
+        if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+          else fprintf(outfile, " (non-unique)\n");
         }
       nptr += namelen + 1;
       }
@@ -4841,7 +5034,7 @@
       PCRE2_SUBSTRING_GET_BYNUMBER(rc, match_data, n, &gotbuffer, &length);
       if (rc < 0)
         {
-        fprintf(outfile, "get substring %d failed (%d): ", n, rc);
+        fprintf(outfile, "Get substring %d failed (%d): ", n, rc);
         PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
         PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
         fprintf(outfile, "\n");
@@ -4863,6 +5056,7 @@
       PCRE2_SIZE length;
       void *gotbuffer;
       int rc;
+      int groupnumber;
       int namelen = strlen((const char *)nptr);
 #if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
       PCRE2_SIZE cnl = namelen;
@@ -4879,10 +5073,14 @@
       if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
 #endif


+      PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+      if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+        fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
       PCRE2_SUBSTRING_GET_BYNAME(rc, match_data, pbuffer, &gotbuffer, &length);
       if (rc < 0)
         {
-        fprintf(outfile, "get substring '%s' failed (%d): ", nptr, rc);
+        fprintf(outfile, "Get substring '%s' failed (%d): ", nptr, rc);
         PCRE2_GET_ERROR_MESSAGE(rc, rc, pbuffer);
         PCHARSV(CASTVAR(void *, pbuffer), 0, rc, FALSE, outfile);
         fprintf(outfile, "\n");
@@ -4891,7 +5089,9 @@
         {
         fprintf(outfile, "  G ");
         PCHARSV(gotbuffer, 0, length, utf, outfile);
-        fprintf(outfile, " (%lu) %s\n", (unsigned long)length, nptr);
+        fprintf(outfile, " (%lu) %s", (unsigned long)length, nptr);
+        if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+          else fprintf(outfile, " (non-unique)\n");
         PCRE2_SUBSTRING_FREE(gotbuffer);
         }
       nptr += namelen + 1;
@@ -5599,61 +5799,71 @@
   }


/* Initialize things that cannot be done until we know which test mode we are
-running in. */
+running in. When HEAP_MATCH_RECURSE is undefined, calling pcre2_set_recursion_
+memory_management() is a no-op, but we call it in order to exercise it. Also
+exercise the general context copying function, which is not otherwise used. */

code_unit_size = test_mode/8;
max_oveccount = DEFAULT_OVECCOUNT;

+/* Use macros to save a lot of duplication. */
+
+#define CREATECONTEXTS \
+  G(general_context,BITS) = G(pcre2_general_context_create_,BITS)(&my_malloc, &my_free, NULL); \
+  G(general_context_copy,BITS) = G(pcre2_general_context_copy_,BITS)(G(general_context,BITS)); \
+  G(default_pat_context,BITS) = G(pcre2_compile_context_create_,BITS)(G(general_context,BITS)); \
+  G(pat_context,BITS) = G(pcre2_compile_context_copy_,BITS)(G(default_pat_context,BITS)); \
+  G(default_dat_context,BITS) = G(pcre2_match_context_create_,BITS)(G(general_context,BITS)); \
+  G(dat_context,BITS) = G(pcre2_match_context_copy_,BITS)(G(default_dat_context,BITS)); \
+  G(match_data,BITS) = G(pcre2_match_data_create_,BITS)(max_oveccount, G(general_context,BITS))
+
+#ifdef HEAP_MATCH_RECURSE
+#define SETRECURSEMEMMAN \
+  (void)G(pcre2_set_recursion_memory_management_,BITS) \
+    (G(default_dat_context,BITS), \
+    &my_stack_malloc, &my_stack_free, NULL)
+#else
+#define SETRECURSEMEMMAN \
+  (void)G(pcre2_set_recursion_memory_management_,BITS)(NULL, NULL, NULL, NULL)
+#endif
+
+/* Call the appropriate functions for the current mode. */
+
 #ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
 if (test_mode == PCRE8_MODE)
   {
-  general_context8 = pcre2_general_context_create_8(&my_malloc, &my_free, NULL);
-  default_pat_context8 = pcre2_compile_context_create_8(general_context8);
-  pat_context8 = pcre2_compile_context_create_8(general_context8);
-  default_dat_context8 = pcre2_match_context_create_8(general_context8);
-  dat_context8 = pcre2_match_context_create_8(general_context8);
-  match_data8 = pcre2_match_data_create_8(max_oveccount, general_context8);
-#ifdef HEAP_MATCH_RECURSE
-  (void)pcre2_set_recursion_memory_management_8(default_dat_context8,
-    &my_stack_malloc, &my_stack_free, NULL);
-#endif
+  CREATECONTEXTS;
+  SETRECURSEMEMMAN;
   }
 #endif


 #ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
 if (test_mode == PCRE16_MODE)
   {
-  general_context16 = pcre2_general_context_create_16(&my_malloc, &my_free,
-    NULL);
-  default_pat_context16 = pcre2_compile_context_create_16(general_context16);
-  pat_context16 = pcre2_compile_context_create_16(general_context16);
-  default_dat_context16 = pcre2_match_context_create_16(general_context16);
-  dat_context16 = pcre2_match_context_create_16(general_context16);
-  match_data16 = pcre2_match_data_create_16(max_oveccount, general_context16);
-#ifdef HEAP_MATCH_RECURSE
-  (void)pcre2_set_recursion_memory_management_16(default_dat_context16,
-    &my_stack_malloc, &my_stack_free, NULL);
-#endif
+  CREATECONTEXTS;
+  SETRECURSEMEMMAN;
   }
 #endif


 #ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
 if (test_mode == PCRE32_MODE)
   {
-  general_context32 = pcre2_general_context_create_32(&my_malloc, &my_free,
-    NULL);
-  default_pat_context32 = pcre2_compile_context_create_32(general_context32);
-  pat_context32 = pcre2_compile_context_create_32(general_context32);
-  default_dat_context32 = pcre2_match_context_create_32(general_context32);
-  dat_context32 = pcre2_match_context_create_32(general_context32);
-  match_data32 = pcre2_match_data_create_32(max_oveccount, general_context32);
-#ifdef HEAP_MATCH_RECURSE
-  (void)pcre2_set_recursion_memory_management_32(default_dat_context32,
-    &my_stack_malloc, &my_stack_free, NULL);
-#endif
+  CREATECONTEXTS;
+  SETRECURSEMEMMAN;
   }
 #endif


+/* Set a default parentheses nest limit that is large enough to run the
+standard tests (this also exercises the function). */
+
+PCRE2_SET_PARENS_NEST_LIMIT(default_pat_context, 220);
+
/* Handle command line modifier settings, sending any error messages to
stderr. We need to know the mode before modifying the context, and it is tidier
to do them all in the same way. */
@@ -5818,36 +6028,39 @@
PCRE2_MATCH_DATA_FREE(match_data);
SUB1(pcre2_code_free, compiled_code);

+PCRE2_JIT_FREE_UNUSED_MEMORY(general_context);
if (jit_stack != NULL)
{
PCRE2_JIT_STACK_FREE(jit_stack);
}

+#define FREECONTEXTS \
+ G(pcre2_general_context_free_,BITS)(G(general_context,BITS)); \
+ G(pcre2_general_context_free_,BITS)(G(general_context_copy,BITS)); \
+ G(pcre2_compile_context_free_,BITS)(G(pat_context,BITS)); \
+ G(pcre2_compile_context_free_,BITS)(G(default_pat_context,BITS)); \
+ G(pcre2_match_context_free_,BITS)(G(dat_context,BITS)); \
+ G(pcre2_match_context_free_,BITS)(G(default_dat_context,BITS))
+
#ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
regfree(&preg);
-pcre2_general_context_free_8(general_context8);
-pcre2_compile_context_free_8(pat_context8);
-pcre2_compile_context_free_8(default_pat_context8);
-pcre2_match_context_free_8(dat_context8);
-pcre2_match_context_free_8(default_dat_context8);
+FREECONTEXTS;
#endif

#ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
free(pbuffer16);
-pcre2_general_context_free_16(general_context16);
-pcre2_compile_context_free_16(pat_context16);
-pcre2_compile_context_free_16(default_pat_context16);
-pcre2_match_context_free_16(dat_context16);
-pcre2_match_context_free_16(default_dat_context16);
+FREECONTEXTS;
#endif

#ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
free(pbuffer32);
-pcre2_general_context_free_32(general_context32);
-pcre2_compile_context_free_32(pat_context32);
-pcre2_compile_context_free_32(default_pat_context32);
-pcre2_match_context_free_32(dat_context32);
-pcre2_match_context_free_32(default_dat_context32);
+FREECONTEXTS;
#endif

#if defined(__VMS)

Modified: code/trunk/testdata/grepoutput
===================================================================
(Binary files differ)

Modified: code/trunk/testdata/testinput17
===================================================================
--- code/trunk/testdata/testinput17    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testinput17    2014-10-31 12:34:34 UTC (rev 128)
@@ -5,7 +5,19 @@
 #forbid_utf
 #pattern posix


+# Test invalid options
+
+/abc/auto_callout
+
 /abc/
+   abc\=find_limits
+
+/abc/
+  abc\=partial_hard
+
+# Real tests
+
+/abc/
     abc
     *** Failers



Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testinput2    2014-10-31 12:34:34 UTC (rev 128)
@@ -2618,7 +2618,7 @@
     YXYYY\=ps
     YXYYYY\=ps


-/\++\KZ|\d+X|9+Y/
+/\++\KZ|\d+X|9+Y/startchar
     ++++123999\=ps
     ++++123999Y\=ps
     ++++Z1234\=ps
@@ -2655,7 +2655,7 @@
    abc\=ps
    abc\=ph


-/abc\K123/
+/abc\K123/startchar
     xyzabc123pqr
     xyzabc12\=ps
     xyzabc12\=ph
@@ -2676,7 +2676,7 @@


/(ab)(x(y)z(cd(*ACCEPT)))pq/B

-/abc\K/aftertext
+/abc\K/aftertext,startchar
     abcdef
     abcdef\=notempty_atstart
     xyzabcdef\=notempty_atstart
@@ -2684,7 +2684,7 @@
     abcdef\=notempty
     xyzabcdef\=notempty


-/^(?:(?=abc)|abc\K)/aftertext
+/^(?:(?=abc)|abc\K)/aftertext,startchar
     abcdef
     abcdef\=notempty_atstart
     ** Failers 
@@ -2923,7 +2923,7 @@
      believe this to be a Perl bug. --/


 /(?>a\Kb)z|(ab)/
-    ab 
+    ab\=startchar 


/(?P<L1>(?P<L2>0|)|(?P>L2)(?P>L1))/

@@ -3643,7 +3643,7 @@
     xxxx123a\=ph
     xxxx123a\=ps


-/123\Kabc/
+/123\Kabc/startchar
     xxxx123a\=ph
     xxxx123a\=ps


@@ -3896,7 +3896,7 @@
/[a[:<:]] should give error/

 /(?=ab\K)/aftertext
-    abcd
+    abcd\=startchar


 /abcd/newline=lf,firstline
     xx\nxabcd
@@ -4006,4 +4006,6 @@
 /\k<A>*(?<A>aa)(?<A>bb)/match_unset_backref,dupnames
     aabb


+/(((((a)))))/parens_nest_limit=2
+
# End of testinput2

Modified: code/trunk/testdata/testinput5
===================================================================
--- code/trunk/testdata/testinput5    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testinput5    2014-10-31 12:34:34 UTC (rev 128)
@@ -1625,6 +1625,9 @@
     scat


 /\X?abc/utf,no_start_optimize
-\xff\x7f\x00\x00\x03\x00\x41\xcc\x80\x41\x{300}\x61\x62\x63\x00\=no_utf_check,offset=06
+    \xff\x7f\x00\x00\x03\x00\x41\xcc\x80\x41\x{300}\x61\x62\x63\x00\=no_utf_check,offset=06


+/\x{100}\x{200}\K\x{300}/utf,startchar
+    \x{100}\x{200}\x{300}
+
 # End of testinput5 


Modified: code/trunk/testdata/testoutput14
===================================================================
--- code/trunk/testdata/testoutput14    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testoutput14    2014-10-31 12:34:34 UTC (rev 128)
@@ -118,7 +118,7 @@


 /(a+)*zz/
     aaaaaaaaaaaaaz\=recursion_limit=10
-Failed: error -50: recursion limit exceeded
+Failed: error -51: recursion limit exceeded


 /(*LIMIT_MATCH=3000)(a+)*zz/I
 Capturing subpattern count = 1
@@ -158,9 +158,9 @@
 Last code unit = 'z'
 Subject length lower bound = 2
     aaaaaaaaaaaaaz
-Failed: error -50: recursion limit exceeded
+Failed: error -51: recursion limit exceeded
     aaaaaaaaaaaaaz\=recursion_limit=1000
-Failed: error -50: recursion limit exceeded
+Failed: error -51: recursion limit exceeded


 /(*LIMIT_RECURSION=10)(*LIMIT_RECURSION=1000)(a+)*zz/I
 Capturing subpattern count = 1
@@ -180,21 +180,21 @@
     aaaaaaaaaaaaaz
 No match
     aaaaaaaaaaaaaz\=recursion_limit=10
-Failed: error -50: recursion limit exceeded
+Failed: error -51: recursion limit exceeded


# These three have infinitely nested recursions.

 /((?2))((?1))/
     abc
-Failed: error -49: nested recursion at the same subject position
+Failed: error -50: nested recursion at the same subject position


 /((?(R2)a+|(?1)b))/
     aaaabcde
-Failed: error -49: nested recursion at the same subject position
+Failed: error -50: nested recursion at the same subject position


 /(?(R)a*(?1)|((?R))b)/
     aaaabcde
-Failed: error -49: nested recursion at the same subject position
+Failed: error -50: nested recursion at the same subject position


# The allusedtext modifier does not work with JIT, which does not maintain
# the leftchar/rightchar data.

Modified: code/trunk/testdata/testoutput17
===================================================================
--- code/trunk/testdata/testoutput17    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testoutput17    2014-10-31 12:34:34 UTC (rev 128)
@@ -5,7 +5,24 @@
 #forbid_utf
 #pattern posix


+# Test invalid options
+
+/abc/auto_callout
+** Ignored with POSIX interface: auto_callout
+
 /abc/
+   abc\=find_limits
+** Ignored with POSIX interface: find_limits
+ 0: abc
+
+/abc/
+  abc\=partial_hard
+** Ignored with POSIX interface: partial_hard
+ 0: abc
+
+# Real tests
+
+/abc/
     abc
  0: abc
     *** Failers


Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testoutput2    2014-10-31 12:34:34 UTC (rev 128)
@@ -244,8 +244,10 @@
  2: b
  3: c
     abcb\=ovector=0
-Matched, but too many substrings
  0: abcb
+ 1: a
+ 2: b
+ 3: c
     abcb\=ovector=1
 Matched, but too many substrings
  0: abcb
@@ -273,8 +275,8 @@
  0: abc
  1: a
     abc\=ovector=0
-Matched, but too many substrings
  0: abc
+ 1: a
     abc\=ovector=1
 Matched, but too many substrings
  0: abc
@@ -287,8 +289,10 @@
  2: a
  3: b
     aba\=ovector=0
-Matched, but too many substrings
  0: aba
+ 1: <unset>
+ 2: a
+ 3: b
     aba\=ovector=1
 Matched, but too many substrings
  0: aba
@@ -989,7 +993,7 @@
  0: abcd
  1: a
  2: d
-copy substring 5 failed (-47): unknown or unset substring
+Copy substring 5 failed (-47): unknown or unset substring


 /(.{20})/I
 Capturing subpattern count = 1
@@ -1043,9 +1047,9 @@
  2: <unset>
  3: f
  1G a (1)
-get substring 2 failed (-47): unknown or unset substring
+Get substring 2 failed (-47): unknown or unset substring
  3G f (1)
-get substring 4 failed (-47): unknown or unset substring
+Get substring 4 failed (-47): unknown or unset substring
  0L adef
  1L a
  2L 
@@ -1058,7 +1062,7 @@
  1G bc (2)
  2G bc (2)
  3G f (1)
-get substring 4 failed (-47): unknown or unset substring
+Get substring 4 failed (-47): unknown or unset substring
  0L bcdef
  1L bc
  2L bc
@@ -4347,18 +4351,19 @@
  1: cd
  2: gh
  1C cd (2)
-  G gh (2) two
+  G gh (2) two (group 2)
     abcdefgh\=copy=one,copy=two
  0: abcdefgh
  1: cd
  2: gh
-  C cd (2) one
-  C gh (2) two
+  C cd (2) one (group 1)
+  C gh (2) two (group 2)
     abcdefgh\=copy=three
  0: abcdefgh
  1: cd
  2: gh
-copy substring 'three' failed (-47): unknown or unset substring
+Number not found for group 'three'
+Copy substring 'three' failed (-47): unknown or unset substring


 /(?P<Tes>)(?P<Test>)/IB
 ------------------------------------------------------------------
@@ -4406,12 +4411,12 @@
  0: zzaa
  1: zz
  2: aa
-  C zz (2) Z
+  C zz (2) Z (group 1)
     zzaa\=copy=A
  0: zzaa
  1: zz
  2: aa
-  C aa (2) A
+  C aa (2) A (group 2)


 /(?P<x>eks)(?P<x>eccs)/I
 Failed: error 143 at offset 15: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
@@ -5712,21 +5717,22 @@
  0: a1
  1: a1
  2: a1
-  C a1 (2) A
+  C a1 (2) A (non-unique)
     a2b\=copy=A
  0: a2b
  1: a2b
  2: <unset>
  3: a2
-  C a2 (2) A
+  C a2 (2) A (non-unique)
     ** Failers
 No match
     a1b\=copy=Z,copy=A
  0: a1
  1: a1
  2: a1
-copy substring 'Z' failed (-47): unknown or unset substring
-  C a1 (2) A
+Number not found for group 'Z'
+Copy substring 'Z' failed (-47): unknown or unset substring
+  C a1 (2) A (non-unique)


/(?|(?<a>)(?<b>)(?<a>)|(?<a>)(?<b>)(?<a>))/I,dupnames
Capturing subpattern count = 3
@@ -5750,7 +5756,7 @@
0: ab
1: a
2: b
- C a (1) A
+ C a (1) A (non-unique)

 /^(?P<A>a)(?P<A>b)|cd/I,dupnames
 Capturing subpattern count = 2
@@ -5763,10 +5769,10 @@
  0: ab
  1: a
  2: b
-  C a (1) A
+  C a (1) A (non-unique)
     cd\=copy=A
  0: cd
-copy substring 'A' failed (-47): unknown or unset substring
+Copy substring 'A' failed (-47): unknown or unset substring


/^(?P<A>a)(?P<A>b)|cd(?P<A>ef)(?P<A>gh)/I,dupnames
Capturing subpattern count = 4
@@ -5783,7 +5789,7 @@
2: <unset>
3: ef
4: gh
- C ef (2) A
+ C ef (2) A (non-unique)

 /^((?P<A>a1)|(?P<A>a2)b)/I,dupnames
 Capturing subpattern count = 3
@@ -5797,21 +5803,22 @@
  0: a1
  1: a1
  2: a1
-  G a1 (2) A
+  G a1 (2) A (non-unique)
     a2b\=get=A
  0: a2b
  1: a2b
  2: <unset>
  3: a2
-  G a2 (2) A
+  G a2 (2) A (non-unique)
     ** Failers
 No match
     a1b\=get=Z,get=A
  0: a1
  1: a1
  2: a1
-get substring 'Z' failed (-47): unknown or unset substring
-  G a1 (2) A
+Number not found for group 'Z'
+Get substring 'Z' failed (-47): unknown or unset substring
+  G a1 (2) A (non-unique)


/^(?P<A>a)(?P<A>b)/I,dupnames
Capturing subpattern count = 2
@@ -5825,7 +5832,7 @@
0: ab
1: a
2: b
- G a (1) A
+ G a (1) A (non-unique)

 /^(?P<A>a)(?P<A>b)|cd/I,dupnames
 Capturing subpattern count = 2
@@ -5838,10 +5845,10 @@
  0: ab
  1: a
  2: b
-  G a (1) A
+  G a (1) A (non-unique)
     cd\=get=A
  0: cd
-get substring 'A' failed (-47): unknown or unset substring
+Get substring 'A' failed (-47): unknown or unset substring


/^(?P<A>a)(?P<A>b)|cd(?P<A>ef)(?P<A>gh)/I,dupnames
Capturing subpattern count = 4
@@ -5858,7 +5865,7 @@
2: <unset>
3: ef
4: gh
- G ef (2) A
+ G ef (2) A (non-unique)

 /(?J)^((?P<A>a1)|(?P<A>a2)b)/I
 Capturing subpattern count = 3
@@ -5873,13 +5880,13 @@
  0: a1
  1: a1
  2: a1
-  C a1 (2) A
+  C a1 (2) A (non-unique)
     a2b\=copy=A
  0: a2b
  1: a2b
  2: <unset>
  3: a2
-  C a2 (2) A
+  C a2 (2) A (non-unique)


/^(?P<A>a) (?J:(?P<B>b)(?P<B>c)) (?P<A>d)/I
Failed: error 143 at offset 37: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
@@ -5910,9 +5917,9 @@
2: b
3: c
4: d
- C a (1) A
- C b (1) B
- C d (1) C
+ C a (1) A (group 1)
+ C b (1) B (non-unique)
+ C d (1) C (group 4)

/^(?P<A>a)?(?(A)a|b)/I
Capturing subpattern count = 1
@@ -7037,8 +7044,8 @@
0: xy
1: x
2: y
- C x (1) abc
- C y (1) xyz
+ C x (1) abc (group 1)
+ C y (1) xyz (group 2)

/(?<abc>x)(?'xyz'y)/I
Capturing subpattern count = 2
@@ -7052,8 +7059,8 @@
0: xy
1: x
2: y
- C x (1) abc
- C y (1) xyz
+ C x (1) abc (group 1)
+ C y (1) xyz (group 2)

/(?<abc'x)(?'xyz'y)/I
Failed: error 142 at offset 6: syntax error in subpattern name (missing terminator)
@@ -7381,8 +7388,8 @@
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\=ovector=0
No match
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4\=ovector=0
-Matched, but too many substrings
0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 1:

 /^a.b/newline=lf
     a\rb
@@ -9218,13 +9225,14 @@
     YXYYYY\=ps
 Partial match: YXYYYY


-/\++\KZ|\d+X|9+Y/
+/\++\KZ|\d+X|9+Y/startchar
     ++++123999\=ps
 Partial match: 123999
     ++++123999Y\=ps
  0: 999Y
     ++++Z1234\=ps
- 0: Z
+ 0: ++++Z
+    ^^^^


 /Z(*F)/
     Z\=ps
@@ -9274,9 +9282,10 @@
    abc\=ph
  0: abc


-/abc\K123/
+/abc\K123/startchar
     xyzabc123pqr
- 0: 123
+ 0: abc123
+    ^^^
     xyzabc12\=ps
 Partial match: abc12
     xyzabc12\=ph
@@ -9370,15 +9379,18 @@
         End
 ------------------------------------------------------------------


-/abc\K/aftertext
+/abc\K/aftertext,startchar
     abcdef
- 0: 
+ 0: abc
+    ^^^
  0+ def
     abcdef\=notempty_atstart
- 0: 
+ 0: abc
+    ^^^
  0+ def
     xyzabcdef\=notempty_atstart
- 0: 
+ 0: abc
+    ^^^
  0+ def
     ** Failers
 No match
@@ -9387,12 +9399,13 @@
     xyzabcdef\=notempty
 No match


-/^(?:(?=abc)|abc\K)/aftertext
+/^(?:(?=abc)|abc\K)/aftertext,startchar
     abcdef
  0: 
  0+ abcdef
     abcdef\=notempty_atstart
- 0: 
+ 0: abc
+    ^^^
  0+ def
     ** Failers 
 No match
@@ -9714,11 +9727,11 @@
     AB\=copy=a
  0: A
  1: A
-  C A (1) a
+  C A (1) a (group 1)
     BA\=copy=a
  0: B
  1: B
-  C B (1) a
+  C B (1) a (group 1)


 /(?|(?<a>A)|(?<b>B))/
 Failed: error 165 at offset 15: different names for subpatterns of the same number are not allowed
@@ -10078,7 +10091,7 @@
      believe this to be a Perl bug. --/


 /(?>a\Kb)z|(ab)/
-    ab 
+    ab\=startchar 
  0: ab
  1: ab


@@ -10883,8 +10896,10 @@
  2: <unset>
  3: baz
     bazfooX\=ovector=0
-Matched, but too many substrings
  0: fooX
+ 1: foo
+ 2: <unset>
+ 3: <unset>
     bazfooX\=ovector=1
 Matched, but too many substrings
  0: fooX
@@ -11888,7 +11903,7 @@
 Partial match, mark=xx: 123a
                         <<<


-/123\Kabc/
+/123\Kabc/startchar
     xxxx123a\=ph
 Partial match: 123a
     xxxx123a\=ps
@@ -13371,7 +13386,7 @@
 Failed: error 130 at offset 4: unknown POSIX class name


 /(?=ab\K)/aftertext
-    abcd
+    abcd\=startchar
 Start of matched string is beyond its end - displaying from end to start.
  0: ab
  0+ abcd
@@ -13589,4 +13604,7 @@
  1: aa
  2: bb


+/(((((a)))))/parens_nest_limit=2
+Failed: error 119 at offset 3: parentheses are too deeply nested
+
# End of testinput2

Modified: code/trunk/testdata/testoutput5
===================================================================
--- code/trunk/testdata/testoutput5    2014-10-28 10:19:50 UTC (rev 127)
+++ code/trunk/testdata/testoutput5    2014-10-31 12:34:34 UTC (rev 128)
@@ -3990,7 +3990,12 @@
  0: sc


 /\X?abc/utf,no_start_optimize
-\xff\x7f\x00\x00\x03\x00\x41\xcc\x80\x41\x{300}\x61\x62\x63\x00\=no_utf_check,offset=06
+    \xff\x7f\x00\x00\x03\x00\x41\xcc\x80\x41\x{300}\x61\x62\x63\x00\=no_utf_check,offset=06
  0: A\x{300}abc


+/\x{100}\x{200}\K\x{300}/utf,startchar
+    \x{100}\x{200}\x{300}
+ 0: \x{100}\x{200}\x{300}
+    ^^^^^^^^^^^^^^
+
 # End of testinput5 


Modified: code/trunk/testdata/testoutput6
===================================================================
(Binary files differ)