[Pcre-svn] [604] code/trunk: Refactoring to reduce stack usa…

トップ ページ
このメッセージを削除
著者: Subversion repository
日付:  
To: pcre-svn
題目: [Pcre-svn] [604] code/trunk: Refactoring to reduce stack usage for possessively quantified subpatterns.
Revision: 604
          http://vcs.pcre.org/viewvc?view=rev&revision=604
Author:   ph10
Date:     2011-06-02 20:04:54 +0100 (Thu, 02 Jun 2011)


Log Message:
-----------
Refactoring to reduce stack usage for possessively quantified subpatterns. Also
fixed a number of bugs related to repeated subpatterns. Some further tidies
consequent on the removal of OP_OPT are also in this patch.

Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/HACKING
    code/trunk/pcre_compile.c
    code/trunk/pcre_dfa_exec.c
    code/trunk/pcre_exec.c
    code/trunk/pcre_internal.h
    code/trunk/pcre_printint.src
    code/trunk/pcre_study.c
    code/trunk/pcretest.c
    code/trunk/testdata/testinput1
    code/trunk/testdata/testinput11
    code/trunk/testdata/testinput2
    code/trunk/testdata/testinput7
    code/trunk/testdata/testoutput1
    code/trunk/testdata/testoutput10
    code/trunk/testdata/testoutput11
    code/trunk/testdata/testoutput2
    code/trunk/testdata/testoutput7


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/ChangeLog    2011-06-02 19:04:54 UTC (rev 604)
@@ -52,6 +52,23 @@
     argument for the match() function, which reduces its stack requirements 
     slightly. This change also fixes an incompatibility with Perl: the pattern
     (?i:([^b]))(?1) should not match "ab", but previously PCRE gave a match.
+    
+10. More internal refactoring has drastically reduced the number of recursive
+    calls to match() for possessively repeated groups such as (abc)++ when 
+    using pcre_exec().
+    
+11. While implementing 10, a number of bugs in the handling of groups were
+    discovered and fixed:
+    
+    (?<=(a)+) was not diagnosed as invalid (non-fixed-length lookbehind).
+    (a|)*(?1) gave a compile-time internal error.
+    ((a|)+)+  did not notice that the outer group could match an empty string. 
+    (^a|^)+   was not marked as anchored.
+    (.*a|.*)+ was not marked as matching at start or after a newline.  
+    
+12. Yet more internal refactoring has removed another argument from the match()
+    function. Special calls to this function are now indicated by setting a 
+    value in a variable in the "match data" data block. 



Version 8.12 15-Jan-2011

Modified: code/trunk/HACKING
===================================================================
--- code/trunk/HACKING    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/HACKING    2011-06-02 19:04:54 UTC (rev 604)
@@ -349,8 +349,9 @@


OP_KET is used for subpatterns that do not repeat indefinitely, while
OP_KETRMIN and OP_KETRMAX are used for indefinite repetitions, minimally or
-maximally respectively. All three are followed by LINK_SIZE bytes giving (as a
-positive number) the offset back to the matching bracket opcode.
+maximally respectively (see below for possessive repetitions). All three are
+followed by LINK_SIZE bytes giving (as a positive number) the offset back to
+the matching bracket opcode.

If a subpattern is quantified such that it is permitted to match zero times, it
is preceded by one of OP_BRAZERO, OP_BRAMINZERO, or OP_SKIPZERO. These are
@@ -377,7 +378,16 @@
that it needs to check for matching an empty string when it hits OP_KETRMIN or
OP_KETRMAX, and if so, to break the loop.

+Possessive brackets
+-------------------

+When a repeated group (capturing or non-capturing) is marked as possessive by
+the "+" notation, e.g. (abc)++, different opcodes are used. Their names all
+have POS on the end, e.g. OP_BRAPOS instead of OP_BRA and OP_SCPBRPOS instead
+of OP_SCBRA. The end of such a group is marked by OP_KETRPOS. If the minimum
+repetition is zero, the group is preceded by OP_BRAPOSZERO.
+
+
Assertions
----------


Modified: code/trunk/pcre_compile.c
===================================================================
--- code/trunk/pcre_compile.c    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_compile.c    2011-06-02 19:04:54 UTC (rev 604)
@@ -545,8 +545,8 @@
 /* Definition to allow mutual recursion */


 static BOOL
-  compile_regex(int, int, uschar **, const uschar **, int *, BOOL, BOOL, int,
-    int *, int *, branch_chain *, compile_data *, int *);
+  compile_regex(int, uschar **, const uschar **, int *, BOOL, BOOL, int, int *,
+    int *, branch_chain *, compile_data *, int *);




@@ -1403,17 +1403,13 @@

 Arguments:
   code         pointer to the start of the group
-  options      pointer to external options
-  optbit       the option bit whose changing is significant, or
-                 zero if none are
   skipassert   TRUE if certain assertions are to be skipped


 Returns:       pointer to the first significant opcode
 */


static const uschar*
-first_significant_code(const uschar *code, int *options, int optbit,
- BOOL skipassert)
+first_significant_code(const uschar *code, BOOL skipassert)
{
for (;;)
{
@@ -1468,7 +1464,7 @@

 Arguments:
   code     points to the start of the pattern (the bracket)
-  options  the compiling options
+  utf8     TRUE in UTF-8 mode
   atend    TRUE if called when the pattern is complete
   cd       the "compile data" structure


@@ -1479,7 +1475,7 @@
*/

static int
-find_fixedlength(uschar *code, int options, BOOL atend, compile_data *cd)
+find_fixedlength(uschar *code, BOOL utf8, BOOL atend, compile_data *cd)
{
int length = -1;

@@ -1496,11 +1492,17 @@
   register int op = *cc;
   switch (op)
     {
+    /* We only need to continue for OP_CBRA (normal capturing bracket) and
+    OP_BRA (normal non-capturing bracket) because the other variants of these
+    opcodes are all concerned with unlimited repeated groups, which of course
+    are not of fixed length. They will cause a -1 response from the default
+    case of this switch. */
+
     case OP_CBRA:
     case OP_BRA:
     case OP_ONCE:
     case OP_COND:
-    d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), options, atend, cd);
+    d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), utf8, atend, cd);
     if (d < 0) return d;
     branchlength += d;
     do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -1509,12 +1511,12 @@


     /* Reached end of a branch; if it's a ket it is the end of a nested
     call. If it's ALT it is an alternation in a nested call. If it is
-    END it's the end of the outer call. All can be handled by the same code. */
+    END it's the end of the outer call. All can be handled by the same code.
+    Note that we must not include the OP_KETRxxx opcodes here, because they
+    all imply an unlimited repeat. */


     case OP_ALT:
     case OP_KET:
-    case OP_KETRMAX:
-    case OP_KETRMIN:
     case OP_END:
     if (length < 0) length = branchlength;
       else if (length != branchlength) return -1;
@@ -1532,7 +1534,7 @@
     cs = ce = (uschar *)cd->start_code + GET(cc, 1);  /* Start subpattern */
     do ce += GET(ce, 1); while (*ce == OP_ALT);       /* End subpattern */
     if (cc > cs && cc < ce) return -1;                /* Recursion */
-    d = find_fixedlength(cs + 2, options, atend, cd);
+    d = find_fixedlength(cs + 2, utf8, atend, cd);
     if (d < 0) return d;
     branchlength += d;
     cc += 1 + LINK_SIZE;
@@ -1575,12 +1577,11 @@
     case OP_CHAR:
     case OP_CHARI:
     case OP_NOT:
-    case OP_NOTI: 
+    case OP_NOTI:
     branchlength++;
     cc += 2;
 #ifdef SUPPORT_UTF8
-    if ((options & PCRE_UTF8) != 0 && cc[-1] >= 0xc0)
-      cc += _pcre_utf8_table4[cc[-1] & 0x3f];
+    if (utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
 #endif
     break;


@@ -1591,8 +1592,7 @@
     branchlength += GET2(cc,1);
     cc += 4;
 #ifdef SUPPORT_UTF8
-    if ((options & PCRE_UTF8) != 0 && cc[-1] >= 0xc0)
-      cc += _pcre_utf8_table4[cc[-1] & 0x3f];
+    if (utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];
 #endif
     break;


@@ -1712,7 +1712,8 @@

/* Handle capturing bracket */

-  else if (c == OP_CBRA)
+  else if (c == OP_CBRA || c == OP_SCBRA ||
+           c == OP_CBRAPOS || c == OP_SCBRAPOS)
     {
     int n = GET2(code, 1+LINK_SIZE);
     if (n == number) return (uschar *)code;
@@ -1954,9 +1955,9 @@
   compile_data *cd)
 {
 register int c;
-for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE);
+for (code = first_significant_code(code + _pcre_OP_lengths[*code], TRUE);
      code < endcode;
-     code = first_significant_code(code + _pcre_OP_lengths[c], NULL, 0, TRUE))
+     code = first_significant_code(code + _pcre_OP_lengths[c], TRUE))
   {
   const uschar *ccode;


@@ -1972,16 +1973,6 @@
     continue;
     }


-  /* Groups with zero repeats can of course be empty; skip them. */
-
-  if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO)
-    {
-    code += _pcre_OP_lengths[c];
-    do code += GET(code, 1); while (*code == OP_ALT);
-    c = *code;
-    continue;
-    }
-
   /* For a recursion/subroutine call, if its end has been reached, which
   implies a subroutine call, we can scan it. */


@@ -2004,9 +1995,33 @@
     continue;
     }


+  /* Groups with zero repeats can of course be empty; skip them. */
+
+  if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO ||
+      c == OP_BRAPOSZERO)
+    {
+    code += _pcre_OP_lengths[c];
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    continue;
+    }
+
+  /* A nested group that is already marked as "could be empty" can just be
+  skipped. */
+
+  if (c == OP_SBRA  || c == OP_SBRAPOS ||
+      c == OP_SCBRA || c == OP_SCBRAPOS)
+    {
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    continue;
+    }
+
   /* For other groups, scan the branches. */


-  if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE || c == OP_COND)
+  if (c == OP_BRA  || c == OP_BRAPOS ||
+      c == OP_CBRA || c == OP_CBRAPOS ||
+      c == OP_ONCE || c == OP_COND)
     {
     BOOL empty_branch;
     if (GET(code, 1) == 0) return TRUE;    /* Hit unclosed bracket */
@@ -2135,6 +2150,7 @@
     case OP_KET:
     case OP_KETRMAX:
     case OP_KETRMIN:
+    case OP_KETRPOS:
     case OP_ALT:
     return TRUE;


@@ -2682,13 +2698,13 @@
return (c != cd->fcc[next]); /* Non-UTF-8 mode */

/* For OP_NOT and OP_NOTI, the data is always a single-byte character. These
- opcodes are not used for multi-byte characters, because they are coded using
+ opcodes are not used for multi-byte characters, because they are coded using
an XCLASS instead. */

   case OP_NOT:
   return (c = *previous) == next;
- 
-  case OP_NOTI: 
+
+  case OP_NOTI:
   if ((c = *previous) == next) return TRUE;
 #ifdef SUPPORT_UTF8
   if (utf8)
@@ -4201,7 +4217,7 @@
     if (*previous == OP_CHAR || *previous == OP_CHARI)
       {
       op_type = (*previous == OP_CHAR)? 0 : OP_STARI - OP_STAR;
-        
+
       /* Deal with UTF-8 characters that take up more than one byte. It's
       easier to write this out separately than try to macrify it. Use c to
       hold the length of the character in bytes, plus 0x80 to flag that it's a
@@ -4246,7 +4262,7 @@
     /* If previous was a single negated character ([^a] or similar), we use
     one of the special opcodes, replacing it. The code is shared with single-
     character repeats by setting opt_type to add a suitable offset into
-    repeat_type. We can also test for auto-possessification. OP_NOT and OP_NOTI 
+    repeat_type. We can also test for auto-possessification. OP_NOT and OP_NOTI
     are currently used only for single-byte chars. */


     else if (*previous == OP_NOT || *previous == OP_NOTI)
@@ -4483,15 +4499,17 @@
       }


     /* If previous was a bracket group, we may have to replicate it in certain
-    cases. */
+    cases. Note that at this point we can encounter only the "basic" BRA and
+    KET opcodes, as this is the place where they get converted into the more
+    special varieties. */


     else if (*previous == OP_BRA  || *previous == OP_CBRA ||
              *previous == OP_ONCE || *previous == OP_COND)
       {
       register int i;
-      int ketoffset = 0;
       int len = (int)(code - previous);
       uschar *bralink = NULL;
+      uschar *brazeroptr = NULL;


       /* Repeating a DEFINE group is pointless */


@@ -4501,17 +4519,6 @@
         goto FAILED;
         }


-      /* If the maximum repeat count is unlimited, find the end of the bracket
-      by scanning through from the start, and compute the offset back to it
-      from the current code pointer. */
-
-      if (repeat_max == -1)
-        {
-        register uschar *ket = previous;
-        do ket += GET(ket, 1); while (*ket != OP_KET);
-        ketoffset = (int)(code - ket);
-        }
-
       /* The case of a zero minimum is special because of the need to stick
       OP_BRAZERO in front of it, and because the group appears once in the
       data, whereas in other cases it appears the minimum number of times. For
@@ -4553,6 +4560,7 @@
             *previous++ = OP_SKIPZERO;
             goto END_REPEAT;
             }
+          brazeroptr = previous;    /* Save for possessive optimizing */
           *previous++ = OP_BRAZERO + repeat_type;
           }


@@ -4717,35 +4725,54 @@
           }
         }


-      /* If the maximum is unlimited, set a repeater in the final copy. We
-      can't just offset backwards from the current code point, because we
-      don't know if there's been an options resetting after the ket. The
-      correct offset was computed above.
+      /* If the maximum is unlimited, set a repeater in the final copy. For
+      ONCE brackets, that's all we need to do.


+      Otherwise, if the quantifier was possessive, we convert the BRA code to
+      the POS form, and the KET code to KETRPOS. (It turns out to be convenient
+      at runtime to detect this kind of subpattern at both the start and at the
+      end.) If the group is preceded by OP_BRAZERO, convert this to
+      OP_BRAPOSZERO. Then cancel the possessive flag so that the default action
+      below, of wrapping everything inside atomic brackets, does not happen.
+
       Then, when we are doing the actual compile phase, check to see whether
-      this group is a non-atomic one that could match an empty string. If so,
-      convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so
-      that runtime checking can be done. [This check is also applied to
-      atomic groups at runtime, but in a different way.] */
+      this group is one that could match an empty string. If so, convert the
+      initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so that runtime
+      checking can be done. [This check is also applied to ONCE groups at
+      runtime, but in a different way.] */


       else
         {
-        uschar *ketcode = code - ketoffset;
+        uschar *ketcode = code - 1 - LINK_SIZE;
         uschar *bracode = ketcode - GET(ketcode, 1);
-        *ketcode = OP_KETRMAX + repeat_type;
-        if (lengthptr == NULL && *bracode != OP_ONCE)
+
+        if (*bracode == OP_ONCE)
+          *ketcode = OP_KETRMAX + repeat_type;
+        else
           {
-          uschar *scode = bracode;
-          do
+          if (possessive_quantifier)
             {
-            if (could_be_empty_branch(scode, ketcode, utf8, cd))
+            *bracode += 1;                   /* Switch to xxxPOS opcodes */
+            *ketcode = OP_KETRPOS;
+            if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO;
+            possessive_quantifier = FALSE;
+            }
+          else *ketcode = OP_KETRMAX + repeat_type;
+
+          if (lengthptr == NULL)
+            {
+            uschar *scode = bracode;
+            do
               {
-              *bracode += OP_SBRA - OP_BRA;
-              break;
+              if (could_be_empty_branch(scode, ketcode, utf8, cd))
+                {
+                *bracode += OP_SBRA - OP_BRA;
+                break;
+                }
+              scode += GET(scode, 1);
               }
-            scode += GET(scode, 1);
+            while (*scode == OP_ALT);
             }
-          while (*scode == OP_ALT);
           }
         }
       }
@@ -5714,9 +5741,8 @@
         is necessary to ensure we correctly detect the start of the pattern in
         both phases.


-        If we are not at the pattern start, compile code to change the ims
-        options if this setting actually changes any of them, and reset the
-        greedy defaults and the case value for firstbyte and reqbyte. */
+        If we are not at the pattern start, reset the greedy defaults and the
+        case value for firstbyte and reqbyte. */


         if (*ptr == CHAR_RIGHT_PARENTHESIS)
           {
@@ -5733,9 +5759,7 @@
             }


           /* Change options at this level, and pass them back for use
-          in subsequent branches. When not at the start of the pattern, this
-          information is also necessary so that a resetting item can be
-          compiled at the end of a group (if we are in a group). */
+          in subsequent branches. */


           *optionsptr = options = newoptions;
           previous = NULL;       /* This item can't be repeated */
@@ -5773,9 +5797,8 @@


     /* Process nested bracketed regex. Assertions may not be repeated, but
     other kinds can be. All their opcodes are >= OP_ONCE. We copy code into a
-    non-register variable in order to be able to pass its address because some
-    compilers complain otherwise. Pass in a new setting for the ims options if
-    they have changed. */
+    non-register variable (tempcode) in order to be able to pass its address
+    because some compilers complain otherwise. */


     previous = (bravalue >= OP_ONCE)? code : NULL;
     *code = bravalue;
@@ -5785,7 +5808,6 @@


     if (!compile_regex(
          newoptions,                   /* The complete new option state */
-         options & PCRE_IMS,           /* The previous ims option state */
          &tempcode,                    /* Where to put code (updated) */
          &ptr,                         /* Input pointer (updated) */
          errorcodeptr,                 /* Where to put an error message */
@@ -6242,7 +6264,6 @@


 Arguments:
   options        option bits, including any changes for this subpattern
-  oldims         previous settings of ims option bits
   codeptr        -> the address of the current code pointer
   ptrptr         -> the address of the current pattern pointer
   errorcodeptr   -> pointer to error code variable
@@ -6260,7 +6281,7 @@
 */


static BOOL
-compile_regex(int options, int oldims, uschar **codeptr, const uschar **ptrptr,
+compile_regex(int options, uschar **codeptr, const uschar **ptrptr,
int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes,
int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd,
int *lengthptr)
@@ -6277,7 +6298,6 @@
int length;
int orig_bracount;
int max_bracount;
-int old_external_options = cd->external_options;
branch_chain bc;

bc.outer = bcptr;
@@ -6301,7 +6321,9 @@

/* If this is a capturing subpattern, add to the chain of open capturing items
so that we can detect them if (*ACCEPT) is encountered. This is also used to
-detect groups that contain recursive back references to themselves. */
+detect groups that contain recursive back references to themselves. Note that
+only OP_CBRA need be tested here; changing this opcode to one of its variants,
+e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */

 if (*code == OP_CBRA)
   {
@@ -6347,15 +6369,6 @@
     return FALSE;
     }


-  /* If the external options have changed during this branch, it means that we
-  are at the top level, and a leading option setting has been encountered. We
-  need to re-set the original option values to take account of this so that,
-  during the pre-compile phase, we know to allow for a re-set at the start of
-  subsequent branches. */
-
-  if (old_external_options != cd->external_options)
-    oldims = cd->external_options & PCRE_IMS;
-
   /* Keep the highest bracket count in case (?| was used and some branch
   has fewer than the rest. */


@@ -6416,7 +6429,8 @@
       {
       int fixed_length;
       *code = OP_END;
-      fixed_length = find_fixedlength(last_branch, options, FALSE, cd);
+      fixed_length = find_fixedlength(last_branch,  (options & PCRE_UTF8) != 0,
+        FALSE, cd);
       DPRINTF(("fixed length = %d\n", fixed_length));
       if (fixed_length == -3)
         {
@@ -6437,9 +6451,7 @@
   of offsets, with the field in the BRA item now becoming an offset to the
   first alternative. If there are no alternatives, it points to the end of the
   group. The length in the terminating ket is always the length of the whole
-  bracketed item. If any of the ims options were changed inside the group,
-  compile a resetting op-code following, except at the very end of the pattern.
-  Return leaving the pointer at the terminating char. */
+  bracketed item. Return leaving the pointer at the terminating char. */


   if (*ptr != CHAR_VERTICAL_LINE)
     {
@@ -6564,7 +6576,6 @@


 Arguments:
   code           points to start of expression (the bracket)
-  options        points to the options setting
   bracket_map    a bitmap of which brackets we are inside while testing; this
                   handles up to substring 31; after that we just have to take
                   the less precise approach
@@ -6574,35 +6585,37 @@
 */


 static BOOL
-is_anchored(register const uschar *code, int *options, unsigned int bracket_map,
+is_anchored(register const uschar *code, unsigned int bracket_map,
   unsigned int backref_map)
 {
 do {
    const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code],
-     options, PCRE_MULTILINE, FALSE);
+     FALSE);
    register int op = *scode;


    /* Non-capturing brackets */


-   if (op == OP_BRA)
+   if (op == OP_BRA  || op == OP_BRAPOS ||
+       op == OP_SBRA || op == OP_SBRAPOS)
      {
-     if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE;
+     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;
      }


    /* Capturing brackets */


-   else if (op == OP_CBRA)
+   else if (op == OP_CBRA  || op == OP_CBRAPOS ||
+            op == OP_SCBRA || op == OP_SCBRAPOS)
      {
      int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
-     if (!is_anchored(scode, options, new_map, backref_map)) return FALSE;
+     if (!is_anchored(scode, new_map, backref_map)) return FALSE;
      }


    /* Other brackets */


    else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
      {
-     if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE;
+     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;
      }


    /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
@@ -6653,7 +6666,7 @@
 {
 do {
    const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code],
-     NULL, 0, FALSE);
+     FALSE);
    register int op = *scode;


    /* If we are at the start of a conditional assertion group, *both* the
@@ -6680,20 +6693,22 @@
        scode += 1 + LINK_SIZE;
        break;
        }
-     scode = first_significant_code(scode, NULL, 0, FALSE);
+     scode = first_significant_code(scode, FALSE);
      op = *scode;
      }


    /* Non-capturing brackets */


-   if (op == OP_BRA)
+   if (op == OP_BRA  || op == OP_BRAPOS ||
+       op == OP_SBRA || op == OP_SBRAPOS)
      {
      if (!is_startline(scode, bracket_map, backref_map)) return FALSE;
      }


    /* Capturing brackets */


-   else if (op == OP_CBRA)
+   else if (op == OP_CBRA  || op == OP_CBRAPOS ||
+            op == OP_SCBRA || op == OP_SCBRAPOS)
      {
      int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
@@ -6743,20 +6758,20 @@


 Arguments:
   code       points to start of expression (the bracket)
-  options    pointer to the options (used to check casing changes)
   inassert   TRUE if in an assertion


 Returns:     -1 or the fixed first char
 */


 static int
-find_firstassertedchar(const uschar *code, int *options, BOOL inassert)
+find_firstassertedchar(const uschar *code, BOOL inassert)
 {
 register int c = -1;
 do {
    int d;
-   const uschar *scode =
-     first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS, TRUE);
+   int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
+             *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? 2:0;
+   const uschar *scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);
    register int op = *scode;


    switch(op)
@@ -6765,31 +6780,44 @@
      return -1;


      case OP_BRA:
+     case OP_BRAPOS:
      case OP_CBRA:
+     case OP_SCBRA:
+     case OP_CBRAPOS:
+     case OP_SCBRAPOS:
      case OP_ASSERT:
      case OP_ONCE:
      case OP_COND:
-     if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0)
+     if ((d = find_firstassertedchar(scode, op == OP_ASSERT)) < 0)
        return -1;
      if (c < 0) c = d; else if (c != d) return -1;
      break;


-     case OP_EXACT:       /* Fall through */
+     case OP_EXACT:
      scode += 2;
-
+     /* Fall through */
+      
      case OP_CHAR:
-     case OP_CHARI:
      case OP_PLUS:
      case OP_MINPLUS:
      case OP_POSPLUS:
      if (!inassert) return -1;
-     if (c < 0)
-       {
-       c = scode[1];
-       if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS;
-       }
-     else if (c != scode[1]) return -1;
+     if (c < 0) c = scode[1];
+       else if (c != scode[1]) return -1;
      break;
+
+     case OP_EXACTI:
+     scode += 2;
+     /* Fall through */
+      
+     case OP_CHARI:
+     case OP_PLUSI:
+     case OP_MINPLUSI:
+     case OP_POSPLUSI:
+     if (!inassert) return -1;
+     if (c < 0) c = scode[1] | REQ_CASELESS;
+       else if (c != scode[1]) return -1;
+     break;
      }


    code += GET(code, 1);
@@ -6939,10 +6967,10 @@


utf8 = (options & PCRE_UTF8) != 0;

-/* Can't support UTF8 unless PCRE has been compiled to include the code. The
-return of an error code from _pcre_valid_utf8() is a new feature, introduced in
-release 8.13. The only use we make of it here is to adjust the offset value to
-the end of the string for a short string error, for compatibility with previous
+/* Can't support UTF8 unless PCRE has been compiled to include the code. The
+return of an error code from _pcre_valid_utf8() is a new feature, introduced in
+release 8.13. The only use we make of it here is to adjust the offset value to
+the end of the string for a short string error, for compatibility with previous
versions. */

#ifdef SUPPORT_UTF8
@@ -7063,9 +7091,8 @@
ptr += skipatstart;
code = cworkspace;
*code = OP_BRA;
-(void)compile_regex(cd->external_options, cd->external_options & PCRE_IMS,
- &code, &ptr, &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd,
- &length);
+(void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE,
+ FALSE, 0, &firstbyte, &reqbyte, NULL, cd, &length);
if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;

 DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
@@ -7137,8 +7164,8 @@
 ptr = (const uschar *)pattern + skipatstart;
 code = (uschar *)codestart;
 *code = OP_BRA;
-(void)compile_regex(re->options, re->options & PCRE_IMS, &code, &ptr,
-  &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, NULL);
+(void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 
+  &firstbyte, &reqbyte, NULL, cd, NULL);
 re->top_bracket = cd->bracount;
 re->top_backref = cd->top_backref;
 re->flags = cd->external_flags;
@@ -7204,7 +7231,8 @@
       uschar *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);
       int end_op = *be;
       *be = OP_END;
-      fixed_length = find_fixedlength(cc, re->options, TRUE, cd);
+      fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,
+        cd);
       *be = end_op;
       DPRINTF(("fixed length = %d\n", fixed_length));
       if (fixed_length < 0)
@@ -7243,13 +7271,12 @@


 if ((re->options & PCRE_ANCHORED) == 0)
   {
-  int temp_options = re->options;   /* May get changed during these scans */
-  if (is_anchored(codestart, &temp_options, 0, cd->backref_map))
+  if (is_anchored(codestart, 0, cd->backref_map))
     re->options |= PCRE_ANCHORED;
   else
     {
     if (firstbyte < 0)
-      firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE);
+      firstbyte = find_firstassertedchar(codestart, FALSE);
     if (firstbyte >= 0)   /* Remove caseless flag for non-caseable chars */
       {
       int ch = firstbyte & 255;


Modified: code/trunk/pcre_dfa_exec.c
===================================================================
--- code/trunk/pcre_dfa_exec.c    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_dfa_exec.c    2011-06-02 19:04:54 UTC (rev 604)
@@ -158,17 +158,18 @@
   0,                             /* Ket                                    */
   0,                             /* KetRmax                                */
   0,                             /* KetRmin                                */
+  0,                             /* KetRpos                                */
   0,                             /* Assert                                 */
   0,                             /* Assert not                             */
   0,                             /* Assert behind                          */
   0,                             /* Assert behind not                      */
   0,                             /* Reverse                                */
-  0, 0, 0, 0,                    /* ONCE, BRA, CBRA, COND                  */
-  0, 0, 0,                       /* SBRA, SCBRA, SCOND                     */
+  0, 0, 0, 0, 0, 0,              /* ONCE, BRA, BRAPOS, CBRA, CBRAPOS, COND */
+  0, 0, 0, 0, 0,                 /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND  */
   0, 0,                          /* CREF, NCREF                            */
   0, 0,                          /* RREF, NRREF                            */
   0,                             /* DEF                                    */
-  0, 0,                          /* BRAZERO, BRAMINZERO                    */
+  0, 0, 0,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */
   0, 0, 0,                       /* MARK, PRUNE, PRUNE_ARG,                */
   0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG,        */
   0, 0, 0, 0, 0                  /* COMMIT, FAIL, ACCEPT, CLOSE, SKIPZERO  */
@@ -224,17 +225,18 @@
   0,                             /* Ket                                    */
   0,                             /* KetRmax                                */
   0,                             /* KetRmin                                */
+  0,                             /* KetRpos                                */
   0,                             /* Assert                                 */
   0,                             /* Assert not                             */
   0,                             /* Assert behind                          */
   0,                             /* Assert behind not                      */
   0,                             /* Reverse                                */
-  0, 0, 0, 0,                    /* ONCE, BRA, CBRA, COND                  */
-  0, 0, 0,                       /* SBRA, SCBRA, SCOND                     */
+  0, 0, 0, 0, 0, 0,              /* ONCE, BRA, BRAPOS, CBRA, CBRAPOS, COND */
+  0, 0, 0, 0, 0,                 /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND  */
   0, 0,                          /* CREF, NCREF                            */
   0, 0,                          /* RREF, NRREF                            */
   0,                             /* DEF                                    */
-  0, 0,                          /* BRAZERO, BRAMINZERO                    */
+  0, 0, 0,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */
   0, 0, 0,                       /* MARK, PRUNE, PRUNE_ARG,                */
   0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG,        */
   0, 0, 0, 0, 0                  /* COMMIT, FAIL, ACCEPT, CLOSE, SKIPZERO  */
@@ -435,7 +437,8 @@
 new_count = 0;


 first_op = this_start_code + 1 + LINK_SIZE +
-  ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0);
+  ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA ||
+    *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS)? 2:0);


 /* The first thing in any (sub) pattern is a bracket of some sort. Push all
 the alternative states onto the list, and find out where the end is. This
@@ -534,7 +537,9 @@
   else
     {
     int length = 1 + LINK_SIZE +
-      ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0);
+      ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA ||
+        *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS)? 
+        2:0);
     do
       {
       ADD_NEW((int)(end_code - start_code + length), 0);
@@ -731,7 +736,12 @@


 /* ========================================================================== */
       /* Reached a closing bracket. If not at the end of the pattern, carry
-      on with the next opcode. Otherwise, unless we have an empty string and
+      on with the next opcode. For repeating opcodes, also add the repeat 
+      state. Note that KETRPOS will always be encountered at the end of the 
+      subpattern, because the possessive subpattern repeats are always handled 
+      using recursive calls. Thus, it never adds any new states.
+       
+      At the end of the (sub)pattern, unless we have an empty string and
       PCRE_NOTEMPTY is set, or PCRE_NOTEMPTY_ATSTART is set and we are at the
       start of the subject, save the match data, shifting up all previous
       matches so we always have the longest first. */
@@ -739,6 +749,7 @@
       case OP_KET:
       case OP_KETRMIN:
       case OP_KETRMAX:
+      case OP_KETRPOS: 
       if (code != end_code)
         {
         ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0);
@@ -2667,6 +2678,96 @@
       break;


       /*-----------------------------------------------------------------*/
+      case OP_BRAPOS:
+      case OP_SBRAPOS:
+      case OP_CBRAPOS:
+      case OP_SCBRAPOS:
+      case OP_BRAPOSZERO: 
+        {
+        int charcount, matched_count;
+        const uschar *local_ptr = ptr;
+        BOOL allow_zero;
+        
+        if (codevalue == OP_BRAPOSZERO)
+          {
+          allow_zero = TRUE;
+          codevalue = *(++code);  /* Codevalue will be one of above BRAs */
+          }
+        else allow_zero = FALSE;          
+        
+        /* Loop to match the subpattern as many times as possible as if it were 
+        a complete pattern. */ 
+           
+        for (matched_count = 0;; matched_count++)
+          {
+          int local_offsets[2];
+          int local_workspace[1000];
+        
+          int rc = internal_dfa_exec(
+            md,                                   /* fixed match data */
+            code,                                 /* this subexpression's code */
+            local_ptr,                            /* where we currently are */
+            (int)(ptr - start_subject),           /* start offset */
+            local_offsets,                        /* offset vector */
+            sizeof(local_offsets)/sizeof(int),    /* size of same */
+            local_workspace,                      /* workspace vector */
+            sizeof(local_workspace)/sizeof(int),  /* size of same */
+            rlevel,                               /* function recursion level */
+            recursing);                           /* pass on regex recursion */
+            
+          /* Failed to match */
+           
+          if (rc < 0) 
+            {
+            if (rc != PCRE_ERROR_NOMATCH) return rc;
+            break;
+            } 
+          
+          /* Matched: break the loop if zero characters matched. */
+           
+          charcount = local_offsets[1] - local_offsets[0];
+          if (charcount == 0) break; 
+          local_ptr += charcount;    /* Advance temporary position ptr */
+          }      
+
+        /* At this point we have matched the subpattern matched_count
+        times, and local_ptr is pointing to the character after the end of the 
+        last match. */ 
+
+        if (matched_count > 0 || allow_zero)
+          { 
+          const uschar *end_subpattern = code;
+          int next_state_offset;
+  
+          do { end_subpattern += GET(end_subpattern, 1); }
+            while (*end_subpattern == OP_ALT);
+          next_state_offset =
+            (int)(end_subpattern - start_code + LINK_SIZE + 1);
+
+          /* Optimization: if there are no more active states, and there
+          are no new states yet set up, then skip over the subject string
+          right here, to save looping. Otherwise, set up the new state to swing
+          into action when the end of the matched substring is reached. */
+
+          if (i + 1 >= active_count && new_count == 0)
+            {
+            ptr = local_ptr;
+            clen = 0;
+            ADD_NEW(next_state_offset, 0);
+            }
+          else
+            {
+            const uschar *p = ptr;
+            const uschar *pp = local_ptr;
+            charcount = pp - p; 
+            while (p < pp) if ((*p++ & 0xc0) == 0x80) charcount--;
+            ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1));
+            }
+          }   
+        }   
+      break;
+ 
+      /*-----------------------------------------------------------------*/
       case OP_ONCE:
         {
         int local_offsets[2];
@@ -2716,7 +2817,7 @@
           /* Optimization: if there are no more active states, and there
           are no new states yet set up, then skip over the subject string
           right here, to save looping. Otherwise, set up the new state to swing
-          into action when the end of the substring is reached. */
+          into action when the end of the matched substring is reached. */


           else if (i + 1 >= active_count && new_count == 0)
             {
@@ -2746,7 +2847,6 @@
             if (repeat_state_offset >= 0)
               { ADD_NEW_DATA(-repeat_state_offset, 0, (charcount - 1)); }
             }
-
           }
         else if (rc != PCRE_ERROR_NOMATCH) return rc;
         }


Modified: code/trunk/pcre_exec.c
===================================================================
--- code/trunk/pcre_exec.c    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_exec.c    2011-06-02 19:04:54 UTC (rev 604)
@@ -57,10 +57,12 @@
 #undef min
 #undef max


-/* Flag bits for the match() function */
+/* Values for setting in md->match_function_type to indicate two special types
+of call to match(). We do it this way to save on using another stack variable,
+as stack usage is to be discouraged. */

-#define match_condassert     0x01  /* Called to check a condition assertion */
-#define match_cbegroup       0x02  /* Could-be-empty unlimited repeat group */
+#define MATCH_CONDASSERT     1  /* Called to check a condition assertion */
+#define MATCH_CBEGROUP       2  /* Could-be-empty unlimited repeat group */


/* Non-error returns from the match() function. Error returns are externally
defined PCRE_ERROR_xxx codes, which are all negative. */
@@ -73,10 +75,11 @@

 #define MATCH_ACCEPT       (-999)
 #define MATCH_COMMIT       (-998)
-#define MATCH_PRUNE        (-997)
-#define MATCH_SKIP         (-996)
-#define MATCH_SKIP_ARG     (-995)
-#define MATCH_THEN         (-994)
+#define MATCH_KETRPOS      (-997)
+#define MATCH_PRUNE        (-996)
+#define MATCH_SKIP         (-995)
+#define MATCH_SKIP_ARG     (-994)
+#define MATCH_THEN         (-993)


/* This is a convenience macro for code that occurs many times. */

@@ -273,7 +276,7 @@
        RM31,  RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40,
        RM41,  RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50,
        RM51,  RM52, RM53, RM54, RM55, RM56, RM57, RM58, RM59, RM60,
-       RM61,  RM62 };
+       RM61,  RM62, RM63, RM64 };


/* These versions of the macros use the stack, as normal. There are debugging
versions and production versions. Note that the "rw" argument of RMATCH isn't
@@ -283,10 +286,10 @@
#define REGISTER register

#ifdef PCRE_DEBUG
-#define RMATCH(ra,rb,rc,rd,re,rf,rw) \
+#define RMATCH(ra,rb,rc,rd,re,rw) \
{ \
printf("match() called in line %d\n", __LINE__); \
- rrc = match(ra,rb,mstart,markptr,rc,rd,re,rf,rdepth+1); \
+ rrc = match(ra,rb,mstart,markptr,rc,rd,re,rdepth+1); \
printf("to line %d\n", __LINE__); \
}
#define RRETURN(ra) \
@@ -295,8 +298,8 @@
return ra; \
}
#else
-#define RMATCH(ra,rb,rc,rd,re,rf,rw) \
- rrc = match(ra,rb,mstart,markptr,rc,rd,re,rf,rdepth+1)
+#define RMATCH(ra,rb,rc,rd,re,rw) \
+ rrc = match(ra,rb,mstart,markptr,rc,rd,re,rdepth+1)
#define RRETURN(ra) return ra
#endif

@@ -309,7 +312,7 @@

#define REGISTER

-#define RMATCH(ra,rb,rc,rd,re,rf,rw)\
+#define RMATCH(ra,rb,rc,rd,re,rw)\
{\
heapframe *newframe = (heapframe *)(pcre_stack_malloc)(sizeof(heapframe));\
if (newframe == NULL) RRETURN(PCRE_ERROR_NOMEMORY);\
@@ -320,7 +323,6 @@
newframe->Xmarkptr = markptr;\
newframe->Xoffset_top = rc;\
newframe->Xeptrb = re;\
- newframe->Xflags = rf;\
newframe->Xrdepth = frame->Xrdepth + 1;\
newframe->Xprevframe = frame;\
frame = newframe;\
@@ -357,7 +359,6 @@
USPTR Xmarkptr;
int Xoffset_top;
eptrblock *Xeptrb;
- int Xflags;
unsigned int Xrdepth;

   /* Function local variables */
@@ -465,10 +466,6 @@
    md          pointer to "static" info for the match
    eptrb       pointer to chain of blocks containing eptr at start of
                  brackets - for testing for empty matches
-   flags       can contain
-                 match_condassert - this is an assertion condition
-                 match_cbegroup - this is the start of an unlimited repeat
-                   group that can match an empty string
    rdepth      the recursion depth


 Returns:       MATCH_MATCH if matched            )  these values are >= 0
@@ -481,7 +478,7 @@
 static int
 match(REGISTER USPTR eptr, REGISTER const uschar *ecode, USPTR mstart,
   const uschar *markptr, int offset_top, match_data *md, eptrblock *eptrb, 
-  int flags, unsigned int rdepth)
+  unsigned int rdepth)
 {
 /* These variables do not need to be preserved over recursion in this function,
 so they can be ordinary variables in all cases. Mark some of them with
@@ -514,7 +511,6 @@
 frame->Xmarkptr = markptr;
 frame->Xoffset_top = offset_top;
 frame->Xeptrb = eptrb;
-frame->Xflags = flags;
 frame->Xrdepth = rdepth;


 /* This is where control jumps back to to effect "recursion" */
@@ -529,7 +525,6 @@
 #define markptr            frame->Xmarkptr
 #define offset_top         frame->Xoffset_top
 #define eptrb              frame->Xeptrb
-#define flags              frame->Xflags
 #define rdepth             frame->Xrdepth


/* Ditto for the local variables */
@@ -587,20 +582,27 @@
#define fi i
#define fc c

+/* Many of the following variables are used only in small blocks of the code.
+My normal style of coding would have declared them within each of those blocks.
+However, in order to accommodate the version of this code that uses an external
+"stack" implemented on the heap, it is easier to declare them all here, so the
+declarations can be cut out in a block. The only declarations within blocks
+below are for variables that do not have to be preserved over a recursive call
+to RMATCH(). */

-#ifdef SUPPORT_UTF8                /* Many of these variables are used only  */
-const uschar *charptr;             /* in small blocks of the code. My normal */
-#endif                             /* style of coding would have declared    */
-const uschar *callpat;             /* them within each of those blocks.      */
-const uschar *data;                /* However, in order to accommodate the   */
-const uschar *next;                /* version of this code that uses an      */
-USPTR         pp;                  /* external "stack" implemented on the    */
-const uschar *prev;                /* heap, it is easier to declare them all */
-USPTR         saved_eptr;          /* here, so the declarations can be cut   */
-                                   /* out in a block. The only declarations  */
-recursion_info new_recursive;      /* within blocks below are for variables  */
-                                   /* that do not have to be preserved over  */
-BOOL cur_is_word;                  /* a recursive call to RMATCH().          */
+#ifdef SUPPORT_UTF8                
+const uschar *charptr;             
+#endif                             
+const uschar *callpat;             
+const uschar *data;                
+const uschar *next;                
+USPTR         pp;                  
+const uschar *prev;                
+USPTR         saved_eptr;          
+                                   
+recursion_info new_recursive;      
+                                   
+BOOL cur_is_word;                  
 BOOL condition;
 BOOL prev_is_word;


@@ -630,6 +632,17 @@
 eptrblock newptrb;
 #endif     /* NO_RECURSE */


+/* To save space on the stack and in the heap frame, I have doubled up on some 
+of the local variables that are used only in localised parts of the code, but 
+still need to be preserved over recursive calls of match(). These macros define 
+the alternative names that are used. */
+
+#define allow_zero    cur_is_word
+#define cbegroup      condition
+#define code_offset   codelink
+#define condassert    condition
+#define matched_once  prev_is_word
+
 /* These statements are here to stop the compiler complaining about unitialized
 variables. */


@@ -667,19 +680,23 @@
if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT);

/* At the start of a group with an unlimited repeat that may match an empty
-string, the match_cbegroup flag is set. When this is the case, add the current
-subject pointer to the chain of such remembered pointers, to be checked when we
-hit the closing ket, in order to break infinite loops that match no characters.
-When match() is called in other circumstances, don't add to the chain. The
-match_cbegroup flag must NOT be used with tail recursion, because the memory
-block that is used is on the stack, so a new one may be required for each
-match(). */
+string, the variable md->match_function_type is set to MATCH_CBEGROUP. It is
+done this way to save having to use another function argument, which would take
+up space on the stack. See also MATCH_CONDASSERT below.

-if ((flags & match_cbegroup) != 0)
+When MATCH_CBEGROUP is set, add the current subject pointer to the chain of
+such remembered pointers, to be checked when we hit the closing ket, in order
+to break infinite loops that match no characters. When match() is called in
+other circumstances, don't add to the chain. The MATCH_CBEGROUP feature must
+NOT be used with tail recursion, because the memory block that is used is on
+the stack, so a new one may be required for each match(). */
+
+if (md->match_function_type == MATCH_CBEGROUP)
{
newptrb.epb_saved_eptr = eptr;
newptrb.epb_prev = eptrb;
eptrb = &newptrb;
+ md->match_function_type = 0;
}

 /* Now start processing the opcodes. */
@@ -688,13 +705,13 @@
   {
   minimize = possessive = FALSE;
   op = *ecode;
-
+  
   switch(op)
     {
     case OP_MARK:
     markptr = ecode + 2;
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode] + ecode[1], offset_top, md,
-      eptrb, flags, RM55);
+      eptrb, RM55);


     /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an
     argument, and we must check whether that argument matches this MARK's
@@ -720,7 +737,7 @@


     case OP_COMMIT:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
-      eptrb, flags, RM52);
+      eptrb, RM52);
     if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE &&
         rrc != MATCH_SKIP && rrc != MATCH_SKIP_ARG &&
         rrc != MATCH_THEN)
@@ -731,13 +748,13 @@


     case OP_PRUNE:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
-      eptrb, flags, RM51);
+      eptrb, RM51);
     if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc);
     MRRETURN(MATCH_PRUNE);


     case OP_PRUNE_ARG:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode] + ecode[1], offset_top, md,
-      eptrb, flags, RM56);
+      eptrb, RM56);
     if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc);
     md->mark = ecode + 2;
     RRETURN(MATCH_PRUNE);
@@ -746,7 +763,7 @@


     case OP_SKIP:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
-      eptrb, flags, RM53);
+      eptrb, RM53);
     if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE && rrc != MATCH_THEN)
       RRETURN(rrc);
     md->start_match_ptr = eptr;   /* Pass back current position */
@@ -754,7 +771,7 @@


     case OP_SKIP_ARG:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode] + ecode[1], offset_top, md,
-      eptrb, flags, RM57);
+      eptrb, RM57);
     if (rrc != MATCH_NOMATCH && rrc != MATCH_PRUNE && rrc != MATCH_THEN)
       RRETURN(rrc);


@@ -773,26 +790,25 @@

     case OP_THEN:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
-      eptrb, flags, RM54);
+      eptrb, RM54);
     if (rrc != MATCH_NOMATCH) RRETURN(rrc);
     md->start_match_ptr = ecode - GET(ecode, 1);
     MRRETURN(MATCH_THEN);


     case OP_THEN_ARG:
     RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode] + ecode[1+LINK_SIZE],
-      offset_top, md, eptrb, flags, RM58);
+      offset_top, md, eptrb, RM58);
     if (rrc != MATCH_NOMATCH) RRETURN(rrc);
     md->start_match_ptr = ecode - GET(ecode, 1);
     md->mark = ecode + LINK_SIZE + 2;
     RRETURN(MATCH_THEN);


-    /* Handle a capturing bracket. If there is space in the offset vector, save
-    the current subject position in the working slot at the top of the vector.
-    We mustn't change the current values of the data slot, because they may be
-    set from a previous iteration of this group, and be referred to by a
-    reference inside the group.
-
-    If the bracket fails to match, we need to restore this value and also the
+    /* Handle a capturing bracket, other than those that are possessive with an
+    unlimited repeat. If there is space in the offset vector, save the current
+    subject position in the working slot at the top of the vector. We mustn't
+    change the current values of the data slot, because they may be set from a
+    previous iteration of this group, and be referred to by a reference inside
+    the group. If we fail to match, we need to restore this value and also the
     values of the final offsets, in case they were set by a previous iteration
     of the same bracket.


@@ -804,7 +820,7 @@
     case OP_SCBRA:
     number = GET2(ecode, 1+LINK_SIZE);
     offset = number << 1;
-
+    
 #ifdef PCRE_DEBUG
     printf("start bracket %d\n", number);
     printf("subject=");
@@ -823,18 +839,18 @@
       md->offset_vector[md->offset_end - number] =
         (int)(eptr - md->start_subject);


-      flags = (op == OP_SCBRA)? match_cbegroup : 0;
-      do
+      for (;;)
         {
-        RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
-          eptrb, flags, RM1);
+        if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP; 
+        RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, 
+          eptrb, RM1);
         if (rrc != MATCH_NOMATCH &&
             (rrc != MATCH_THEN || md->start_match_ptr != ecode))
           RRETURN(rrc);
         md->capture_last = save_capture_last;
         ecode += GET(ecode, 1);
+        if (*ecode != OP_ALT) break; 
         }
-      while (*ecode == OP_ALT);


       DPRINTF(("bracket %d failed\n", number));


@@ -857,40 +873,39 @@
     /* VVVVVVVVVVVVVVVVVVVVVVVVV */
     /* VVVVVVVVVVVVVVVVVVVVVVVVV */


-    /* Non-capturing bracket. Loop for all the alternatives. When we get to the
-    final alternative within the brackets, we would return the result of a
-    recursive call to match() whatever happened. We can reduce stack usage by
-    turning this into a tail recursion, except in the case when match_cbegroup
-    is set.*/
+    /* Non-capturing bracket, except for possessive with unlimited repeat. Loop
+    for all the alternatives. When we get to the final alternative within the
+    brackets, we would return the result of a recursive call to match()
+    whatever happened. We can reduce stack usage by turning this into a tail
+    recursion, except in the case of a possibly empty group.*/


     case OP_BRA:
     case OP_SBRA:
     DPRINTF(("start non-capturing bracket\n"));
-    flags = (op >= OP_SBRA)? match_cbegroup : 0;
     for (;;)
       {
       if (ecode[GET(ecode, 1)] != OP_ALT)   /* Final alternative */
         {
-        if (flags == 0)    /* Not a possibly empty group */
+        if (op >= OP_SBRA)   /* Possibly empty group */
           {
-          ecode += _pcre_OP_lengths[*ecode];
-          DPRINTF(("bracket 0 tail recursion\n"));
-          goto TAIL_RECURSE;
-          }
-
-        /* Possibly empty group; can't use tail recursion. */
-
-        RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, eptrb, 
-          flags, RM48);
-        if (rrc == MATCH_NOMATCH) md->mark = markptr;
-        RRETURN(rrc);
+          md->match_function_type = MATCH_CBEGROUP; 
+          RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, eptrb, 
+            RM48);
+          if (rrc == MATCH_NOMATCH) md->mark = markptr;
+          RRETURN(rrc);
+          } 
+        /* Not a possibly empty group; use tail recursion */
+        ecode += _pcre_OP_lengths[*ecode];
+        DPRINTF(("bracket 0 tail recursion\n"));
+        goto TAIL_RECURSE;
         }


       /* For non-final alternatives, continue the loop for a NOMATCH result;
       otherwise return. */


+      if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
       RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, eptrb, 
-        flags, RM2);
+        RM2);
       if (rrc != MATCH_NOMATCH &&
           (rrc != MATCH_THEN || md->start_match_ptr != ecode))
         RRETURN(rrc);
@@ -898,6 +913,143 @@
       }
     /* Control never reaches here. */


+    /* Handle possessive capturing brackets with an unlimited repeat. We come 
+    here from BRAZERO with allow_zero set TRUE. The offset_vector values are
+    handled similarly to the normal case above. However, the matching is
+    different. The end of these brackets will always be OP_KETRPOS, which
+    returns MATCH_KETRPOS without going further in the pattern. By this means
+    we can handle the group by iteration rather than recursion, thereby
+    reducing the amount of stack needed. */
+    
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    allow_zero = FALSE;
+    
+    POSSESSIVE_CAPTURE:
+    number = GET2(ecode, 1+LINK_SIZE);
+    offset = number << 1;
+
+#ifdef PCRE_DEBUG
+    printf("start possessive bracket %d\n", number);
+    printf("subject=");
+    pchars(eptr, 16, TRUE, md);
+    printf("\n");
+#endif
+
+    if (offset < md->offset_max)
+      {
+      matched_once = FALSE;
+      code_offset = ecode - md->start_code; 
+
+      save_offset1 = md->offset_vector[offset];
+      save_offset2 = md->offset_vector[offset+1];
+      save_offset3 = md->offset_vector[md->offset_end - number];
+      save_capture_last = md->capture_last;
+
+      DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
+ 
+      /* Each time round the loop, save the current subject position for use 
+      when the group matches. For MATCH_MATCH, the group has matched, so we 
+      restart it with a new subject starting position, remembering that we had 
+      at least one match. For MATCH_NOMATCH, carry on with the alternatives, as 
+      usual. If we haven't matched any alternatives in any iteration, check to 
+      see if a previous iteration matched. If so, the group has matched; 
+      continue from afterwards. Otherwise it has failed; restore the previous 
+      capture values before returning NOMATCH. */
+ 
+      for (;;)
+        {
+        md->offset_vector[md->offset_end - number] =
+          (int)(eptr - md->start_subject);
+        if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;   
+        RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
+          eptrb, RM63);
+        if (rrc == MATCH_KETRPOS)
+          {
+          offset_top = md->end_offset_top;
+          eptr = md->end_match_ptr;
+          ecode = md->start_code + code_offset; 
+          save_capture_last = md->capture_last;
+          matched_once = TRUE; 
+          continue;  
+          }  
+        if (rrc != MATCH_NOMATCH &&
+            (rrc != MATCH_THEN || md->start_match_ptr != ecode))
+          RRETURN(rrc);
+        md->capture_last = save_capture_last;
+        ecode += GET(ecode, 1);
+        if (*ecode != OP_ALT) break; 
+        }
+        
+      if (!matched_once)
+        { 
+        md->offset_vector[offset] = save_offset1;
+        md->offset_vector[offset+1] = save_offset2;
+        md->offset_vector[md->offset_end - number] = save_offset3;
+        }
+        
+      if (rrc != MATCH_THEN) md->mark = markptr;
+      if (allow_zero || matched_once)
+        { 
+        ecode += 1 + LINK_SIZE;
+        break;
+        }  
+ 
+      RRETURN(MATCH_NOMATCH);
+      }
+      
+    /* FALL THROUGH ... Insufficient room for saving captured contents. Treat
+    as a non-capturing bracket. */
+
+    /* VVVVVVVVVVVVVVVVVVVVVVVVV */
+    /* VVVVVVVVVVVVVVVVVVVVVVVVV */
+
+    DPRINTF(("insufficient capture room: treat as non-capturing\n"));
+
+    /* VVVVVVVVVVVVVVVVVVVVVVVVV */
+    /* VVVVVVVVVVVVVVVVVVVVVVVVV */
+
+    /* Non-capturing possessive bracket with unlimited repeat. We come here 
+    from BRAZERO with allow_zero = TRUE. The code is similar to the above,
+    without the capturing complication. It is written out separately for speed
+    and cleanliness. */
+
+    case OP_BRAPOS:
+    case OP_SBRAPOS:
+    allow_zero = FALSE; 
+    
+    POSSESSIVE_NON_CAPTURE:
+    matched_once = FALSE;
+    code_offset = ecode - md->start_code; 
+
+    for (;;)
+      {
+      if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;   
+      RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md,
+        eptrb, RM64);
+      if (rrc == MATCH_KETRPOS)
+        {
+        eptr = md->end_match_ptr;
+        ecode = md->start_code + code_offset; 
+        matched_once = TRUE; 
+        continue;  
+        }  
+      if (rrc != MATCH_NOMATCH &&
+          (rrc != MATCH_THEN || md->start_match_ptr != ecode))
+        RRETURN(rrc);
+      ecode += GET(ecode, 1);
+      if (*ecode != OP_ALT) break; 
+      }
+
+    if (matched_once || allow_zero) 
+      {
+      ecode += 1 + LINK_SIZE;
+      break;
+      } 
+    RRETURN(MATCH_NOMATCH);
+
+    /* Control never reaches here. */
+
     /* Conditional group: compilation checked that there are no more than
     two branches. If the condition is false, skipping the first branch takes us
     past the end if there is only one branch, but that's OK because that is
@@ -906,7 +1058,7 @@


     case OP_COND:
     case OP_SCOND:
-    codelink= GET(ecode, 1);
+    codelink = GET(ecode, 1);


     /* Because of the way auto-callout works during compile, a callout item is
     inserted between OP_COND and an assertion condition. */
@@ -1081,13 +1233,13 @@
       }


     /* The condition is an assertion. Call match() to evaluate it - setting
-    the final argument match_condassert causes it to stop at the end of an
-    assertion. */
+    md->match_function_type to MATCH_CONDASSERT causes it to stop at the end of
+    an assertion. */


     else
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL,
-          match_condassert, RM3);
+      md->match_function_type = MATCH_CONDASSERT; 
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM3);
       if (rrc == MATCH_MATCH)
         {
         condition = TRUE;
@@ -1108,22 +1260,19 @@


     /* We are now at the branch that is to be obeyed. As there is only one,
     we can use tail recursion to avoid using another stack frame, except when
-    match_cbegroup is required for an unlimited repeat of a possibly empty
-    group. If the second alternative doesn't exist, we can just plough on. */
+    we have an unlimited repeat of a possibly empty group. If the second
+    alternative doesn't exist, we can just plough on. */


     if (condition || *ecode == OP_ALT)
       {
       ecode += 1 + LINK_SIZE;
       if (op == OP_SCOND)        /* Possibly empty group */
         {
-        RMATCH(eptr, ecode, offset_top, md, eptrb, match_cbegroup, RM49);
+        md->match_function_type = MATCH_CBEGROUP; 
+        RMATCH(eptr, ecode, offset_top, md, eptrb, RM49);
         RRETURN(rrc);
         }
-      else                       /* Group must match something */
-        {
-        flags = 0;
-        goto TAIL_RECURSE;
-        }
+      else goto TAIL_RECURSE;
       }
     else                         /* Condition false & no alternative */
       {
@@ -1201,14 +1350,25 @@
     matching won't pass the KET for an assertion. If any one branch matches,
     the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
     start of each branch to move the current point backwards, so the code at
-    this level is identical to the lookahead case. */
+    this level is identical to the lookahead case. When the assertion is part 
+    of a condition, we want to return immediately afterwards. The caller of 
+    this incarnation of the match() function will have set MATCH_CONDASSERT in 
+    md->match_function type, and one of these opcodes will be the first opcode 
+    that is processed. We use a local variable that is preserved over calls to 
+    match() to remember this case. */


     case OP_ASSERT:
     case OP_ASSERTBACK:
+    if (md->match_function_type == MATCH_CONDASSERT)
+      {
+      condassert = TRUE;
+      md->match_function_type = 0;
+      }
+    else condassert = FALSE;        
+     
     do
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, 0,
-        RM4);
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4);
       if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)
         {
         mstart = md->start_match_ptr;   /* In case \K reset it */
@@ -1220,11 +1380,12 @@
       ecode += GET(ecode, 1);
       }
     while (*ecode == OP_ALT);
+     
     if (*ecode == OP_KET) MRRETURN(MATCH_NOMATCH);


     /* If checking an assertion for a condition, return MATCH_MATCH. */


-    if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
+    if (condassert) RRETURN(MATCH_MATCH);


     /* Continue from after the assertion, updating the offsets high water
     mark, since extracts may have been taken during the assertion. */
@@ -1240,10 +1401,16 @@


     case OP_ASSERT_NOT:
     case OP_ASSERTBACK_NOT:
+    if (md->match_function_type == MATCH_CONDASSERT)
+      {
+      condassert = TRUE;
+      md->match_function_type = 0;
+      }
+    else condassert = FALSE;        
+
     do
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, 0,
-        RM5);
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5);
       if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) MRRETURN(MATCH_NOMATCH);
       if (rrc == MATCH_SKIP || rrc == MATCH_PRUNE || rrc == MATCH_COMMIT)
         {
@@ -1257,8 +1424,8 @@
       }
     while (*ecode == OP_ALT);


-    if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
-
+    if (condassert) RRETURN(MATCH_MATCH);  /* Condition assertion */
+     
     ecode += 1 + LINK_SIZE;
     continue;


@@ -1376,11 +1543,12 @@
       restore the offset and recursion data. */


       DPRINTF(("Recursing into group %d\n", new_recursive.group_num));
-      flags = (*callpat >= OP_SBRA)? match_cbegroup : 0;
+      cbegroup = (*callpat >= OP_SBRA);
       do
         {
+        if (cbegroup) md->match_function_type = MATCH_CBEGROUP;
         RMATCH(eptr, callpat + _pcre_OP_lengths[*callpat], offset_top,
-          md, eptrb, flags, RM6);
+          md, eptrb, RM6);
         if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)
           {
           DPRINTF(("Recursion matched\n"));
@@ -1427,7 +1595,7 @@


     do
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, 0, RM7);
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM7);
       if (rrc == MATCH_MATCH)  /* Note: _not_ MATCH_ACCEPT */
         {
         mstart = md->start_match_ptr;
@@ -1470,18 +1638,17 @@


     if (*ecode == OP_KETRMIN)
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, 0, RM8);
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM8);
       if (rrc != MATCH_NOMATCH) RRETURN(rrc);
       ecode = prev;
-      flags = 0;
       goto TAIL_RECURSE;
       }
     else  /* OP_KETRMAX */
       {
-      RMATCH(eptr, prev, offset_top, md, eptrb, match_cbegroup, RM9);
+      md->match_function_type = MATCH_CBEGROUP; 
+      RMATCH(eptr, prev, offset_top, md, eptrb, RM9);
       if (rrc != MATCH_NOMATCH) RRETURN(rrc);
       ecode += 1 + LINK_SIZE;
-      flags = 0;
       goto TAIL_RECURSE;
       }
     /* Control never gets here */
@@ -1498,40 +1665,44 @@
     at all - i.e. it could be ()* or ()? or even (){0} in the pattern. Brackets
     with fixed upper repeat limits are compiled as a number of copies, with the
     optional ones preceded by BRAZERO or BRAMINZERO. */
-
+     
     case OP_BRAZERO:
-      {
-      next = ecode+1;
-      RMATCH(eptr, next, offset_top, md, eptrb, 0, RM10);
-      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-      do next += GET(next,1); while (*next == OP_ALT);
-      ecode = next + 1 + LINK_SIZE;
-      }
+    next = ecode + 1;
+    RMATCH(eptr, next, offset_top, md, eptrb, RM10);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    do next += GET(next, 1); while (*next == OP_ALT);
+    ecode = next + 1 + LINK_SIZE;
     break;
-
+    
     case OP_BRAMINZERO:
-      {
-      next = ecode+1;
-      do next += GET(next, 1); while (*next == OP_ALT);
-      RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, eptrb, 0, RM11);
-      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-      ecode++;
-      }
+    next = ecode + 1;
+    do next += GET(next, 1); while (*next == OP_ALT);
+    RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, eptrb, RM11);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    ecode++;
     break;


     case OP_SKIPZERO:
-      {
-      next = ecode+1;
-      do next += GET(next,1); while (*next == OP_ALT);
-      ecode = next + 1 + LINK_SIZE;
-      }
+    next = ecode+1;
+    do next += GET(next,1); while (*next == OP_ALT);
+    ecode = next + 1 + LINK_SIZE;
     break;
+    
+    /* BRAPOSZERO occurs before a possessive bracket group. Don't do anything
+    here; just jump to the group, with allow_zero set TRUE. */
+    
+    case OP_BRAPOSZERO:
+    op = *(++ecode); 
+    allow_zero = TRUE;
+    if (op == OP_CBRAPOS || op == OP_SCBRAPOS) goto POSSESSIVE_CAPTURE;
+      goto POSSESSIVE_NON_CAPTURE;


     /* End of a group, repeated or non-repeating. */


     case OP_KET:
     case OP_KETRMIN:
     case OP_KETRMAX:
+    case OP_KETRPOS: 
     prev = ecode - GET(ecode, 1);


     /* If this was a group that remembered the subject start, in order to break
@@ -1566,7 +1737,8 @@
     a recurse into group 0, so it won't be picked up here. Instead, we catch it
     when the OP_END is reached. Other recursion is handled here. */


-    if (*prev == OP_CBRA || *prev == OP_SCBRA)
+    if (*prev == OP_CBRA || *prev == OP_SCBRA ||
+        *prev == OP_CBRAPOS || *prev == OP_SCBRAPOS)
       {
       number = GET2(prev, 1+LINK_SIZE);
       offset = number << 1;
@@ -1612,21 +1784,31 @@
       ecode += 1 + LINK_SIZE;
       break;
       }
+      
+    /* OP_KETRPOS is a possessive repeating ket. Remember the current position, 
+    and return the MATCH_KETRPOS. This makes it possible to do the repeats one
+    at a time from the outer level, thus saving stack. */
+    
+    if (*ecode == OP_KETRPOS)
+      {  
+      md->end_match_ptr = eptr;
+      md->end_offset_top = offset_top; 
+      RRETURN(MATCH_KETRPOS);
+      }  


-    /* The repeating kets try the rest of the pattern or restart from the
-    preceding bracket, in the appropriate order. In the second case, we can use
-    tail recursion to avoid using another stack frame, unless we have an
+    /* The normal repeating kets try the rest of the pattern or restart from
+    the preceding bracket, in the appropriate order. In the second case, we can
+    use tail recursion to avoid using another stack frame, unless we have an
     unlimited repeat of a group that can match an empty string. */


-    flags = (*prev >= OP_SBRA)? match_cbegroup : 0;
-
     if (*ecode == OP_KETRMIN)
       {
-      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, 0, RM12);
+      RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM12);
       if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-      if (flags != 0)    /* Could match an empty string */
+      if (*prev >= OP_SBRA)    /* Could match an empty string */
         {
-        RMATCH(eptr, prev, offset_top, md, eptrb, flags, RM50);
+        md->match_function_type = MATCH_CBEGROUP; 
+        RMATCH(eptr, prev, offset_top, md, eptrb, RM50);
         RRETURN(rrc);
         }
       ecode = prev;
@@ -1634,10 +1816,10 @@
       }
     else  /* OP_KETRMAX */
       {
-      RMATCH(eptr, prev, offset_top, md, eptrb, flags, RM13);
+      if (*prev >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP; 
+      RMATCH(eptr, prev, offset_top, md, eptrb, RM13);
       if (rrc != MATCH_NOMATCH) RRETURN(rrc);
       ecode += 1 + LINK_SIZE;
-      flags = 0;
       goto TAIL_RECURSE;
       }
     /* Control never gets here */
@@ -2324,7 +2506,7 @@
       for (fi = min;; fi++)
         {
         int slength; 
-        RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM14);
+        RMATCH(eptr, ecode, offset_top, md, eptrb, RM14);
         if (rrc != MATCH_NOMATCH) RRETURN(rrc);
         if (fi >= max) MRRETURN(MATCH_NOMATCH);
         if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0)
@@ -2354,7 +2536,7 @@
         }
       while (eptr >= pp)
         {
-        RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM15);
+        RMATCH(eptr, ecode, offset_top, md, eptrb, RM15);
         if (rrc != MATCH_NOMATCH) RRETURN(rrc);
         eptr -= length;
         }
@@ -2464,7 +2646,7 @@
           {
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM16);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM16);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -2489,7 +2671,7 @@
           {
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM17);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM17);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -2535,7 +2717,7 @@
             }
           for (;;)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM18);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM18);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (eptr-- == pp) break;        /* Stop if tried at original pos */
             BACKCHAR(eptr);
@@ -2558,7 +2740,7 @@
             }
           while (eptr >= pp)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM19);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM19);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             eptr--;
             }
@@ -2634,7 +2816,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM20);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM20);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -2667,7 +2849,7 @@
           }
         for(;;)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM21);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM21);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (eptr-- == pp) break;        /* Stop if tried at original pos */
           if (utf8) BACKCHAR(eptr);
@@ -2880,7 +3062,7 @@
           {
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM22);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM22);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr <= md->end_subject - length &&
@@ -2922,7 +3104,7 @@


           for(;;)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM23);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM23);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (eptr == pp) { MRRETURN(MATCH_NOMATCH); }
 #ifdef SUPPORT_UCP
@@ -2976,7 +3158,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM24);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM24);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -3006,7 +3188,7 @@


         while (eptr >= pp)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM25);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM25);
           eptr--;
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           }
@@ -3035,7 +3217,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM26);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM26);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -3064,7 +3246,7 @@


         while (eptr >= pp)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM27);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM27);
           eptr--;
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           }
@@ -3236,7 +3418,7 @@
           register unsigned int d;
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM28);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM28);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -3255,7 +3437,7 @@
           {
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM29);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM29);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -3296,7 +3478,7 @@
         if (possessive) continue;
         for(;;)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM30);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM30);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (eptr-- == pp) break;        /* Stop if tried at original pos */
             BACKCHAR(eptr);
@@ -3319,7 +3501,7 @@
           if (possessive) continue;
           while (eptr >= pp)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM31);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM31);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             eptr--;
             }
@@ -3376,7 +3558,7 @@
           register unsigned int d;
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM32);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM32);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -3394,7 +3576,7 @@
           {
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM33);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM33);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -3434,7 +3616,7 @@
           if (possessive) continue;
           for(;;)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM34);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM34);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (eptr-- == pp) break;        /* Stop if tried at original pos */
             BACKCHAR(eptr);
@@ -3457,7 +3639,7 @@
           if (possessive) continue;
           while (eptr >= pp)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM35);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM35);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             eptr--;
             }
@@ -4255,7 +4437,7 @@
           case PT_ANY:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM36);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM36);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4271,7 +4453,7 @@
           case PT_LAMP:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM37);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM37);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4291,7 +4473,7 @@
           case PT_GC:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM38);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM38);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4309,7 +4491,7 @@
           case PT_PC:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM39);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM39);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4327,7 +4509,7 @@
           case PT_SC:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM40);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM40);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4345,7 +4527,7 @@
           case PT_ALNUM:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM59);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM59);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4364,7 +4546,7 @@
           case PT_SPACE:    /* Perl space */
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM60);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM60);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4384,7 +4566,7 @@
           case PT_PXSPACE:  /* POSIX space */
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM61);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM61);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4404,7 +4586,7 @@
           case PT_WORD:
           for (fi = min;; fi++)
             {
-            RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM62);
+            RMATCH(eptr, ecode, offset_top, md, eptrb, RM62);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max) MRRETURN(MATCH_NOMATCH);
             if (eptr >= md->end_subject)
@@ -4436,7 +4618,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM41);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM41);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -4468,7 +4650,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM42);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM42);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -4631,7 +4813,7 @@
         {
         for (fi = min;; fi++)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM43);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM43);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (fi >= max) MRRETURN(MATCH_NOMATCH);
           if (eptr >= md->end_subject)
@@ -4929,7 +5111,7 @@
         if (possessive) continue;
         for(;;)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM44);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM44);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (eptr-- == pp) break;        /* Stop if tried at original pos */
           if (utf8) BACKCHAR(eptr);
@@ -4970,7 +5152,7 @@


         for(;;)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM45);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM45);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (eptr-- == pp) break;        /* Stop if tried at original pos */
           for (;;)                        /* Move back over one extended */
@@ -5263,7 +5445,7 @@
         if (possessive) continue;
         for(;;)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM46);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM46);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           if (eptr-- == pp) break;        /* Stop if tried at original pos */
           BACKCHAR(eptr);
@@ -5476,7 +5658,7 @@
         if (possessive) continue;
         while (eptr >= pp)
           {
-          RMATCH(eptr, ecode, offset_top, md, eptrb, 0, RM47);
+          RMATCH(eptr, ecode, offset_top, md, eptrb, RM47);
           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
           eptr--;
           if (ctype == OP_ANYNL && eptr > pp  && *eptr == '\n' && 
@@ -5519,7 +5701,7 @@
   LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17)
   LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33)
   LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52)
-  LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58)
+  LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58) LBL(63) LBL(64)
 #ifdef SUPPORT_UTF8
   LBL(16) LBL(18) LBL(20) LBL(21) LBL(22) LBL(23) LBL(28) LBL(30)
   LBL(32) LBL(34) LBL(42) LBL(46)
@@ -6120,8 +6302,8 @@
   md->start_match_ptr = start_match;
   md->start_used_ptr = start_match;
   md->match_call_count = 0;
-  rc = match(start_match, md->start_code, start_match, NULL, 2, md, NULL,
-    0, 0);
+  md->match_function_type = 0; 
+  rc = match(start_match, md->start_code, start_match, NULL, 2, md, NULL, 0);
   if (md->hitend && start_partial == NULL) start_partial = md->start_used_ptr;


switch(rc)
@@ -6244,7 +6426,7 @@

/* Set the return code to the number of captured strings, or 0 if there are
too many to fit into the vector. */
-
+
rc = md->offset_overflow? 0 : md->end_offset_top/2;

/* If there is space, set up the whole thing as substring 0. The value of

Modified: code/trunk/pcre_internal.h
===================================================================
--- code/trunk/pcre_internal.h    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_internal.h    2011-06-02 19:04:54 UTC (rev 604)
@@ -582,10 +582,6 @@
 #endif



-/* These are the public options that can change during matching. */
-
-#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
-
/* Private flags containing information about the compiled regex. They used to
live at the top end of the options word, but that got almost full, so now they
are in a 16-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as
@@ -1325,7 +1321,7 @@

/* The following sets of 13 opcodes must always be kept in step because
the offset from the first one is used to generate the others. */
-
+
/**** Single characters, caseful, must precede the caseless ones ****/

   OP_STAR,           /* 33 The maximizing and minimizing versions of */
@@ -1345,7 +1341,7 @@
   OP_POSUPTO,        /* 45 Possessified upto, caseful */


   /**** Single characters, caseless, must follow the caseful ones */
-   
+
   OP_STARI,          /* 46 */
   OP_MINSTARI,       /* 47 */
   OP_PLUSI,          /* 48 */
@@ -1382,7 +1378,7 @@
   OP_NOTPOSUPTO,     /* 71 */


   /**** Negated single character, caseless; must follow the caseful ones ****/
-   
+
   OP_NOTSTARI,       /* 72 */
   OP_NOTMINSTARI,    /* 73 */
   OP_NOTPLUSI,       /* 74 */
@@ -1400,7 +1396,7 @@
   OP_NOTPOSUPTOI,    /* 84 */


   /**** Character types ****/
-   
+
   OP_TYPESTAR,       /* 85 The maximizing and minimizing versions of */
   OP_TYPEMINSTAR,    /* 86 these six opcodes must come in pairs, with */
   OP_TYPEPLUS,       /* 87 the minimizing one second. These codes must */
@@ -1418,7 +1414,7 @@
   OP_TYPEPOSUPTO,    /* 97 */


/* These are used for character classes and back references; only the
- first six are the same as the sets above. */
+ first six are the same as the sets above. */

   OP_CRSTAR,         /* 98 The maximizing and minimizing versions of */
   OP_CRMINSTAR,      /* 99 all these opcodes must come in pairs, with */
@@ -1447,61 +1443,69 @@
   OP_KET,            /* 114 End of group that doesn't have an unbounded repeat */
   OP_KETRMAX,        /* 115 These two must remain together and in this */
   OP_KETRMIN,        /* 116 order. They are for groups the repeat for ever. */
+  OP_KETRPOS,        /* 117 Possessive unlimited repeat. */


/* The assertions must come before BRA, CBRA, ONCE, and COND.*/

-  OP_ASSERT,         /* 117 Positive lookahead */
-  OP_ASSERT_NOT,     /* 118 Negative lookahead */
-  OP_ASSERTBACK,     /* 119 Positive lookbehind */
-  OP_ASSERTBACK_NOT, /* 120 Negative lookbehind */
-  OP_REVERSE,        /* 121 Move pointer back - used in lookbehind assertions */
+  OP_ASSERT,         /* 118 Positive lookahead */
+  OP_ASSERT_NOT,     /* 119 Negative lookahead */
+  OP_ASSERTBACK,     /* 120 Positive lookbehind */
+  OP_ASSERTBACK_NOT, /* 121 Negative lookbehind */
+  OP_REVERSE,        /* 122 Move pointer back - used in lookbehind assertions */


- /* ONCE, BRA, CBRA, and COND must come after the assertions, with ONCE first,
- as there's a test for >= ONCE for a subpattern that isn't an assertion. */
+ /* ONCE, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come after the assertions,
+ with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an
+ assertion. The POS versions must immediately follow the non-POS versions in
+ each case. */

-  OP_ONCE,           /* 122 Atomic group */
-  OP_BRA,            /* 123 Start of non-capturing bracket */
-  OP_CBRA,           /* 124 Start of capturing bracket */
-  OP_COND,           /* 125 Conditional group */
+  OP_ONCE,           /* 123 Atomic group */
+  OP_BRA,            /* 124 Start of non-capturing bracket */
+  OP_BRAPOS,         /* 125 Ditto, with unlimited, possessive repeat */
+  OP_CBRA,           /* 126 Start of capturing bracket */
+  OP_CBRAPOS,        /* 127 Ditto, with unlimited, possessive repeat */
+  OP_COND,           /* 128 Conditional group */


- /* These three must follow the previous three, in the same order. There's a
+ /* These five must follow the previous five, in the same order. There's a
check for >= SBRA to distinguish the two sets. */

-  OP_SBRA,           /* 126 Start of non-capturing bracket, check empty  */
-  OP_SCBRA,          /* 127 Start of capturing bracket, check empty */
-  OP_SCOND,          /* 128 Conditional group, check empty */
+  OP_SBRA,           /* 129 Start of non-capturing bracket, check empty  */
+  OP_SBRAPOS,        /* 130 Ditto, with unlimited, possessive repeat */
+  OP_SCBRA,          /* 131 Start of capturing bracket, check empty */
+  OP_SCBRAPOS,       /* 132 Ditto, with unlimited, possessive repeat */
+  OP_SCOND,          /* 133 Conditional group, check empty */


/* The next two pairs must (respectively) be kept together. */

-  OP_CREF,           /* 129 Used to hold a capture number as condition */
-  OP_NCREF,          /* 130 Same, but generated by a name reference*/
-  OP_RREF,           /* 131 Used to hold a recursion number as condition */
-  OP_NRREF,          /* 132 Same, but generated by a name reference*/
-  OP_DEF,            /* 133 The DEFINE condition */
+  OP_CREF,           /* 134 Used to hold a capture number as condition */
+  OP_NCREF,          /* 135 Same, but generated by a name reference*/
+  OP_RREF,           /* 136 Used to hold a recursion number as condition */
+  OP_NRREF,          /* 137 Same, but generated by a name reference*/
+  OP_DEF,            /* 138 The DEFINE condition */


-  OP_BRAZERO,        /* 134 These two must remain together and in this */
-  OP_BRAMINZERO,     /* 135 order. */
+  OP_BRAZERO,        /* 139 These two must remain together and in this */
+  OP_BRAMINZERO,     /* 140 order. */
+  OP_BRAPOSZERO,     /* 141 */ 


/* These are backtracking control verbs */

-  OP_MARK,           /* 136 always has an argument */
-  OP_PRUNE,          /* 137 */
-  OP_PRUNE_ARG,      /* 138 same, but with argument */
-  OP_SKIP,           /* 139 */
-  OP_SKIP_ARG,       /* 140 same, but with argument */
-  OP_THEN,           /* 141 */
-  OP_THEN_ARG,       /* 142 same, but with argument */
-  OP_COMMIT,         /* 143 */
+  OP_MARK,           /* 142 always has an argument */
+  OP_PRUNE,          /* 143 */
+  OP_PRUNE_ARG,      /* 144 same, but with argument */
+  OP_SKIP,           /* 145 */
+  OP_SKIP_ARG,       /* 146 same, but with argument */
+  OP_THEN,           /* 147 */
+  OP_THEN_ARG,       /* 148 same, but with argument */
+  OP_COMMIT,         /* 149 */


/* These are forced failure and success verbs */

-  OP_FAIL,           /* 144 */
-  OP_ACCEPT,         /* 145 */
-  OP_CLOSE,          /* 146 Used before OP_ACCEPT to close open captures */
+  OP_FAIL,           /* 150 */
+  OP_ACCEPT,         /* 151 */
+  OP_CLOSE,          /* 152 Used before OP_ACCEPT to close open captures */


/* This is used to skip a subpattern with a {0} quantifier */

-  OP_SKIPZERO,       /* 147 */
+  OP_SKIPZERO,       /* 153 */


/* This is not an opcode, but is used to check that tables indexed by opcode
are the correct length, in order to catch updating errors - there have been
@@ -1517,7 +1521,7 @@

/* This macro defines textual names for all the opcodes. These are used only
for debugging, and some of them are only partial names. The macro is referenced
-only in pcre_printint.c, which fills out the full names in many cases (and in
+only in pcre_printint.c, which fills out the full names in many cases (and in
some cases doesn't actually use these names at all). */

 #define OP_NAME_LIST \
@@ -1543,11 +1547,15 @@
   "*", "*?", "+", "+?", "?", "??", "{", "{",                      \
   "class", "nclass", "xclass", "Ref", "Refi",                     \
   "Recurse", "Callout",                                           \
-  "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not",     \
-  "AssertB", "AssertB not", "Reverse",                            \
-  "Once", "Bra", "CBra", "Cond", "SBra", "SCBra", "SCond",        \
+  "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos",                  \
+  "Assert", "Assert not", "AssertB", "AssertB not", "Reverse",    \
+  "Once",                                                         \
+  "Bra", "BraPos", "CBra", "CBraPos",                             \
+  "Cond",                                                         \
+  "SBra", "SBraPos", "SCBra", "SCBraPos",                         \
+  "SCond",                                                        \
   "Cond ref", "Cond nref", "Cond rec", "Cond nrec", "Cond def",   \
-  "Brazero", "Braminzero",                                        \
+  "Brazero", "Braminzero", "Braposzero",                          \
   "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP",                  \
   "*THEN", "*THEN", "*COMMIT", "*FAIL", "*ACCEPT",                \
   "Close", "Skip zero"
@@ -1607,6 +1615,7 @@
   1+LINK_SIZE,                   /* Ket                                    */ \
   1+LINK_SIZE,                   /* KetRmax                                */ \
   1+LINK_SIZE,                   /* KetRmin                                */ \
+  1+LINK_SIZE,                   /* KetRpos                                */ \
   1+LINK_SIZE,                   /* Assert                                 */ \
   1+LINK_SIZE,                   /* Assert not                             */ \
   1+LINK_SIZE,                   /* Assert behind                          */ \
@@ -1614,15 +1623,19 @@
   1+LINK_SIZE,                   /* Reverse                                */ \
   1+LINK_SIZE,                   /* ONCE                                   */ \
   1+LINK_SIZE,                   /* BRA                                    */ \
+  1+LINK_SIZE,                   /* BRAPOS                                 */ \
   3+LINK_SIZE,                   /* CBRA                                   */ \
+  3+LINK_SIZE,                   /* CBRAPOS                                */ \
   1+LINK_SIZE,                   /* COND                                   */ \
   1+LINK_SIZE,                   /* SBRA                                   */ \
+  1+LINK_SIZE,                   /* SBRAPOS                                */ \
   3+LINK_SIZE,                   /* SCBRA                                  */ \
+  3+LINK_SIZE,                   /* SCBRAPOS                               */ \
   1+LINK_SIZE,                   /* SCOND                                  */ \
   3, 3,                          /* CREF, NCREF                            */ \
   3, 3,                          /* RREF, NRREF                            */ \
   1,                             /* DEF                                    */ \
-  1, 1,                          /* BRAZERO, BRAMINZERO                    */ \
+  1, 1, 1,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */ \
   3, 1, 3,                       /* MARK, PRUNE, PRUNE_ARG                 */ \
   1, 3,                          /* SKIP, SKIP_ARG                         */ \
   1+LINK_SIZE, 3+LINK_SIZE,      /* THEN, THEN_ARG                         */ \
@@ -1803,6 +1816,7 @@
   int    end_offset_top;        /* Highwater mark at end of match */
   int    capture_last;          /* Most recent capture number */
   int    start_offset;          /* The start offset value */
+  int    match_function_type;   /* Set for certain special calls of MATCH() */ 
   eptrblock *eptrchain;         /* Chain of eptrblocks for tail recursions */
   int    eptrn;                 /* Next free eptrblock */
   recursion_info *recursive;    /* Linked list of recursion data */


Modified: code/trunk/pcre_printint.src
===================================================================
--- code/trunk/pcre_printint.src    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_printint.src    2011-06-02 19:04:54 UTC (rev 604)
@@ -238,16 +238,21 @@
     continue;


     case OP_CBRA:
+    case OP_CBRAPOS: 
     case OP_SCBRA:
+    case OP_SCBRAPOS: 
     if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
       else fprintf(f, "    ");
     fprintf(f, "%s %d", OP_names[*code], GET2(code, 1+LINK_SIZE));
     break;


     case OP_BRA:
+    case OP_BRAPOS: 
     case OP_SBRA:
+    case OP_SBRAPOS: 
     case OP_KETRMAX:
     case OP_KETRMIN:
+    case OP_KETRPOS: 
     case OP_ALT:
     case OP_KET:
     case OP_ASSERT:


Modified: code/trunk/pcre_study.c
===================================================================
--- code/trunk/pcre_study.c    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcre_study.c    2011-06-02 19:04:54 UTC (rev 604)
@@ -85,7 +85,8 @@
 register int branchlength = 0;
 register uschar *cc = (uschar *)code + 1 + LINK_SIZE;


-if (*code == OP_CBRA || *code == OP_SCBRA) cc += 2;
+if (*code == OP_CBRA || *code == OP_SCBRA ||
+    *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += 2;


 /* Scan along the opcodes for this branch. If we get to the end of the
 branch, check the length against that of the other branches. */
@@ -119,6 +120,10 @@
     case OP_SCBRA:
     case OP_BRA:
     case OP_SBRA:
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    case OP_BRAPOS:
+    case OP_SBRAPOS:
     case OP_ONCE:
     d = find_minlength(cc, startcode, options);
     if (d < 0) return d;
@@ -135,6 +140,7 @@
     case OP_KET:
     case OP_KETRMAX:
     case OP_KETRMIN:
+    case OP_KETRPOS: 
     case OP_END:
     if (length < 0 || (!had_recurse && branchlength < length))
       length = branchlength;
@@ -179,6 +185,7 @@


     case OP_BRAZERO:
     case OP_BRAMINZERO:
+    case OP_BRAPOSZERO:
     case OP_SKIPZERO:
     cc += _pcre_OP_lengths[*cc];
     do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -375,7 +382,13 @@
       min = 0;
       cc++;
       break;
-
+      
+      case OP_CRPLUS:                                                           
+      case OP_CRMINPLUS:                                                        
+      min = 1;                                                                  
+      cc++;                                                                     
+      break;    
+       
       case OP_CRRANGE:
       case OP_CRMINRANGE:
       min = GET2(cc, 1);
@@ -664,8 +677,11 @@


 do
   {
-  const uschar *tcode = code + (((int)*code == OP_CBRA)? 3:1) + LINK_SIZE;
   BOOL try_next = TRUE;
+  const uschar *tcode = code + 1 + LINK_SIZE;
+  
+  if (*code == OP_CBRA || *code == OP_SCBRA ||
+      *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += 2;


   while (try_next)    /* Loop for items in this branch */
     {
@@ -686,6 +702,10 @@
       case OP_SBRA:
       case OP_CBRA:
       case OP_SCBRA:
+      case OP_BRAPOS:
+      case OP_SBRAPOS:
+      case OP_CBRAPOS:
+      case OP_SCBRAPOS:
       case OP_ONCE:
       case OP_ASSERT:
       rc = set_start_bits(tcode, start_bits, utf8, cd);
@@ -712,6 +732,7 @@
       case OP_KET:
       case OP_KETRMAX:
       case OP_KETRMIN:
+      case OP_KETRPOS: 
       return SSB_CONTINUE;


       /* Skip over callout */
@@ -733,6 +754,7 @@


       case OP_BRAZERO:
       case OP_BRAMINZERO:
+      case OP_BRAPOSZERO:
       if (set_start_bits(++tcode, start_bits, utf8, cd) == SSB_FAIL)
         return SSB_FAIL;
 /* =========================================================================


Modified: code/trunk/pcretest.c
===================================================================
--- code/trunk/pcretest.c    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/pcretest.c    2011-06-02 19:04:54 UTC (rev 604)
@@ -2910,7 +2910,10 @@
             break;     


             default:
-            fprintf(outfile, "Error %d (%s)\n", count, errtexts[-count]);
+            if (count < 0 && (-count) < sizeof(errtexts)/sizeof(const char *)) 
+              fprintf(outfile, "Error %d (%s)\n", count, errtexts[-count]);
+            else 
+              fprintf(outfile, "Error %d (Unexpected value)\n", count);   
             break;
             }



Modified: code/trunk/testdata/testinput1
===================================================================
--- code/trunk/testdata/testinput1    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testinput1    2011-06-02 19:04:54 UTC (rev 604)
@@ -4130,4 +4130,7 @@
     abcdef
     ABCDEF  


+/((a|)+)+Z/
+    Z
+
 /-- End of testinput1 --/


Modified: code/trunk/testdata/testinput11
===================================================================
--- code/trunk/testdata/testinput11    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testinput11    2011-06-02 19:04:54 UTC (rev 604)
@@ -516,4 +516,72 @@
     Ba
     ba


+/^(?&t)*+(?(DEFINE)(?<t>a))\w$/
+    aaaaaaX
+    ** Failers 
+    aaaaaa 
+
+/^(?&t)*(?(DEFINE)(?<t>a))\w$/
+    aaaaaaX
+    aaaaaa 
+
+/^(a)*+(\w)/
+    aaaaX
+    YZ 
+    ** Failers 
+    aaaa
+
+/^(?:a)*+(\w)/
+    aaaaX
+    YZ 
+    ** Failers 
+    aaaa
+
+/^(a)++(\w)/
+    aaaaX
+    ** Failers 
+    aaaa
+    YZ 
+
+/^(?:a)++(\w)/
+    aaaaX
+    ** Failers 
+    aaaa
+    YZ 
+
+/^(a)?+(\w)/
+    aaaaX
+    YZ 
+
+/^(?:a)?+(\w)/
+    aaaaX
+    YZ 
+
+/^(a){2,}+(\w)/
+    aaaaX
+    ** Failers
+    aaa
+    YZ 
+
+/^(?:a){2,}+(\w)/
+    aaaaX
+    ** Failers
+    aaa
+    YZ 
+
+/(a|)*(?1)b/
+    b
+    ab
+    aab  
+
+/(a)++(?1)b/
+    ** Failers
+    ab 
+    aab
+
+/(a)*+(?1)b/
+    ** Failers
+    ab
+    aab  
+
 /-- End of testinput11 --/


Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testinput2    2011-06-02 19:04:54 UTC (rev 604)
@@ -3593,4 +3593,70 @@


/^abc$/BZm

+/^(a)*+(\w)/S
+    aaaaX
+    ** Failers 
+    aaaa
+
+/^(?:a)*+(\w)/S
+    aaaaX
+    ** Failers 
+    aaaa
+
+/(a)++1234/SDZ
+
+/([abc])++1234/SI
+
+/(?<=(abc)+)X/
+
+/(^ab)/I
+
+/(^ab)++/I
+
+/(^ab|^)+/I
+
+/(^ab|^)++/I
+
+/(?:^ab)/I
+
+/(?:^ab)++/I
+
+/(?:^ab|^)+/I
+
+/(?:^ab|^)++/I
+
+/(.*ab)/I
+
+/(.*ab)++/I
+
+/(.*ab|.*)+/I
+
+/(.*ab|.*)++/I
+
+/(?:.*ab)/I
+
+/(?:.*ab)++/I
+
+/(?:.*ab|.*)+/I
+
+/(?:.*ab|.*)++/I
+
+/(?=a)[bcd]/I
+
+/((?=a))[bcd]/I
+
+/((?=a))+[bcd]/I
+
+/((?=a))++[bcd]/I
+
+/(?=a+)[bcd]/iI
+
+/(?=a+?)[bcd]/iI
+
+/(?=a++)[bcd]/iI
+
+/(?=a{3})[bcd]/iI
+
+/(abc)\1+/S
+
 /-- End of testinput2 --/


Modified: code/trunk/testdata/testinput7
===================================================================
--- code/trunk/testdata/testinput7    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testinput7    2011-06-02 19:04:54 UTC (rev 604)
@@ -4607,4 +4607,34 @@
     abc\>4
     abc\>-4 


+/^(?:a)++\w/
+     aaaab
+     ** Failers 
+     aaaa 
+     bbb 
+
+/^(?:aa|(?:a)++\w)/
+     aaaab
+     aaaa 
+     ** Failers 
+     bbb 
+
+/^(?:a)*+\w/
+     aaaab
+     bbb 
+     ** Failers 
+     aaaa 
+
+/^(a)++\w/
+     aaaab
+     ** Failers 
+     aaaa 
+     bbb 
+
+/^(a|)++\w/
+     aaaab
+     ** Failers 
+     aaaa 
+     bbb 
+
 /-- End of testinput7 --/


Modified: code/trunk/testdata/testoutput1
===================================================================
--- code/trunk/testdata/testoutput1    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testoutput1    2011-06-02 19:04:54 UTC (rev 604)
@@ -6744,4 +6744,10 @@
     ABCDEF  
  0: BCD


+/((a|)+)+Z/
+    Z
+ 0: Z
+ 1: 
+ 2: 
+
 /-- End of testinput1 --/


Modified: code/trunk/testdata/testoutput10
===================================================================
--- code/trunk/testdata/testoutput10    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testoutput10    2011-06-02 19:04:54 UTC (rev 604)
@@ -111,17 +111,15 @@
 ------------------------------------------------------------------


 /(x)*+/BM
-Memory allocation (code space): 24
+Memory allocation (code space): 18
 ------------------------------------------------------------------
-  0  20 Bra
-  3  14 Once
-  6     Brazero
-  7   7 CBra 1
- 12     x
- 14   7 KetRmax
- 17  14 Ket
- 20  20 Ket
- 23     End
+  0  14 Bra
+  3     Braposzero
+  4   7 CBraPos 1
+  9     x
+ 11   7 KetRpos
+ 14  14 Ket
+ 17     End
 ------------------------------------------------------------------


/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/BM

Modified: code/trunk/testdata/testoutput11
===================================================================
--- code/trunk/testdata/testoutput11    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testoutput11    2011-06-02 19:04:54 UTC (rev 604)
@@ -994,4 +994,135 @@
     ba
 No match


+/^(?&t)*+(?(DEFINE)(?<t>a))\w$/
+    aaaaaaX
+ 0: aaaaaaX
+    ** Failers 
+No match
+    aaaaaa 
+No match
+
+/^(?&t)*(?(DEFINE)(?<t>a))\w$/
+    aaaaaaX
+ 0: aaaaaaX
+    aaaaaa 
+ 0: aaaaaa
+
+/^(a)*+(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: a
+ 2: X
+    YZ 
+ 0: Y
+ 1: <unset>
+ 2: Y
+    ** Failers 
+No match
+    aaaa
+No match
+
+/^(?:a)*+(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: X
+    YZ 
+ 0: Y
+ 1: Y
+    ** Failers 
+No match
+    aaaa
+No match
+
+/^(a)++(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: a
+ 2: X
+    ** Failers 
+No match
+    aaaa
+No match
+    YZ 
+No match
+
+/^(?:a)++(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: X
+    ** Failers 
+No match
+    aaaa
+No match
+    YZ 
+No match
+
+/^(a)?+(\w)/
+    aaaaX
+ 0: aa
+ 1: a
+ 2: a
+    YZ 
+ 0: Y
+ 1: <unset>
+ 2: Y
+
+/^(?:a)?+(\w)/
+    aaaaX
+ 0: aa
+ 1: a
+    YZ 
+ 0: Y
+ 1: Y
+
+/^(a){2,}+(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: a
+ 2: X
+    ** Failers
+No match
+    aaa
+No match
+    YZ 
+No match
+
+/^(?:a){2,}+(\w)/
+    aaaaX
+ 0: aaaaX
+ 1: X
+    ** Failers
+No match
+    aaa
+No match
+    YZ 
+No match
+
+/(a|)*(?1)b/
+    b
+ 0: b
+ 1: 
+    ab
+ 0: ab
+ 1: 
+    aab  
+ 0: aab
+ 1: 
+
+/(a)++(?1)b/
+    ** Failers
+No match
+    ab 
+No match
+    aab
+No match
+
+/(a)*+(?1)b/
+    ** Failers
+No match
+    ab
+No match
+    aab  
+No match
+
 /-- End of testinput11 --/


Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testoutput2    2011-06-02 19:04:54 UTC (rev 604)
@@ -2990,13 +2990,11 @@
 /(x)*+/DZ
 ------------------------------------------------------------------
         Bra
-        Once
-        Brazero
-        CBra 1
+        Braposzero
+        CBraPos 1
         x
-        KetRmax
+        KetRpos
         Ket
-        Ket
         End
 ------------------------------------------------------------------
 Capturing subpattern count = 1
@@ -11356,4 +11354,197 @@
         End
 ------------------------------------------------------------------


+/^(a)*+(\w)/S
+    aaaaX
+ 0: aaaaX
+ 1: a
+ 2: X
+    ** Failers 
+No match
+    aaaa
+No match
+
+/^(?:a)*+(\w)/S
+    aaaaX
+ 0: aaaaX
+ 1: X
+    ** Failers 
+No match
+    aaaa
+No match
+
+/(a)++1234/SDZ
+------------------------------------------------------------------
+        Bra
+        CBraPos 1
+        a
+        KetRpos
+        1234
+        Ket
+        End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = '4'
+Subject length lower bound = 5
+No set of starting bytes
+
+/([abc])++1234/SI
+Capturing subpattern count = 1
+No options
+No first char
+Need char = '4'
+Subject length lower bound = 5
+Starting byte set: a b c 
+
+/(?<=(abc)+)X/
+Failed: lookbehind assertion is not fixed length at offset 10
+
+/(^ab)/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+
+/(^ab)++/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+
+/(^ab|^)+/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+
+/(^ab|^)++/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+
+/(?:^ab)/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(?:^ab)++/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(?:^ab|^)+/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(?:^ab|^)++/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(.*ab)/I
+Capturing subpattern count = 1
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/(.*ab)++/I
+Capturing subpattern count = 1
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/(.*ab|.*)+/I
+Capturing subpattern count = 1
+No options
+First char at start or follows newline
+No need char
+
+/(.*ab|.*)++/I
+Capturing subpattern count = 1
+No options
+First char at start or follows newline
+No need char
+
+/(?:.*ab)/I
+Capturing subpattern count = 0
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/(?:.*ab)++/I
+Capturing subpattern count = 0
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/(?:.*ab|.*)+/I
+Capturing subpattern count = 0
+No options
+First char at start or follows newline
+No need char
+
+/(?:.*ab|.*)++/I
+Capturing subpattern count = 0
+No options
+First char at start or follows newline
+No need char
+
+/(?=a)[bcd]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/((?=a))[bcd]/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/((?=a))+[bcd]/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/((?=a))++[bcd]/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(?=a+)[bcd]/iI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+No need char
+
+/(?=a+?)[bcd]/iI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+No need char
+
+/(?=a++)[bcd]/iI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+No need char
+
+/(?=a{3})[bcd]/iI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+Need char = 'a' (caseless)
+
+/(abc)\1+/S
+
 /-- End of testinput2 --/


Modified: code/trunk/testdata/testoutput7
===================================================================
--- code/trunk/testdata/testoutput7    2011-05-27 10:14:09 UTC (rev 603)
+++ code/trunk/testdata/testoutput7    2011-06-02 19:04:54 UTC (rev 604)
@@ -7697,4 +7697,55 @@
     abc\>-4 
 Error -24 (bad offset value)


+/^(?:a)++\w/
+     aaaab
+ 0: aaaab
+     ** Failers 
+No match
+     aaaa 
+No match
+     bbb 
+No match
+
+/^(?:aa|(?:a)++\w)/
+     aaaab
+ 0: aaaab
+ 1: aa
+     aaaa 
+ 0: aa
+     ** Failers 
+No match
+     bbb 
+No match
+
+/^(?:a)*+\w/
+     aaaab
+ 0: aaaab
+     bbb 
+ 0: b
+     ** Failers 
+No match
+     aaaa 
+No match
+
+/^(a)++\w/
+     aaaab
+ 0: aaaab
+     ** Failers 
+No match
+     aaaa 
+No match
+     bbb 
+No match
+
+/^(a|)++\w/
+     aaaab
+ 0: aaaab
+     ** Failers 
+No match
+     aaaa 
+No match
+     bbb 
+No match
+
 /-- End of testinput7 --/