Diff for /embedaddon/pcre/pcre_compile.c between versions 1.1 and 1.1.1.5

version 1.1, 2012/02/21 23:05:51 version 1.1.1.5, 2014/06/15 19:46:03
Line 6 Line 6
 and semantics are as close as possible to those of the Perl 5 language.  and semantics are as close as possible to those of the Perl 5 language.
   
                        Written by Philip Hazel                         Written by Philip Hazel
           Copyright (c) 1997-2011 University of Cambridge           Copyright (c) 1997-2013 University of Cambridge
   
 -----------------------------------------------------------------------------  -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
Line 53  supporting internal functions that are not used by oth Line 53  supporting internal functions that are not used by oth
 #include "pcre_internal.h"  #include "pcre_internal.h"
   
   
/* When PCRE_DEBUG is defined, we need the pcre_printint() function, which is/* When PCRE_DEBUG is defined, we need the pcre(16|32)_printint() function, which
also used by pcretest. PCRE_DEBUG is not defined when building a productionis also used by pcretest. PCRE_DEBUG is not defined when building a production
library. */library. We do not need to select pcre16_printint.c specially, because the
 COMPILE_PCREx macro will already be appropriately set. */
   
 #ifdef PCRE_DEBUG  #ifdef PCRE_DEBUG
#include "pcre_printint.src"/* pcre_printint.c should not include any headers */
 #define PCRE_INCLUDED
 #include "pcre_printint.c"
 #undef PCRE_INCLUDED
 #endif  #endif
   
   
 /* Macro for setting individual bits in class bitmaps. */  /* Macro for setting individual bits in class bitmaps. */
   
#define SETBIT(a,b) a[b/8] |= (1 << (b%8))#define SETBIT(a,b) a[(b)/8] |= (1 << ((b)&7))
   
 /* Maximum length value to check against when making sure that the integer that  /* Maximum length value to check against when making sure that the integer that
 holds the compiled pattern length does not overflow. We make it a bit less than  holds the compiled pattern length does not overflow. We make it a bit less than
Line 73  to check them every time. */ Line 77  to check them every time. */
   
 #define OFLOW_MAX (INT_MAX - 20)  #define OFLOW_MAX (INT_MAX - 20)
   
   /* Definitions to allow mutual recursion */
   
   static int
     add_list_to_class(pcre_uint8 *, pcre_uchar **, int, compile_data *,
       const pcre_uint32 *, unsigned int);
   
   static BOOL
     compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int,
       pcre_uint32 *, pcre_int32 *, pcre_uint32 *, pcre_int32 *, branch_chain *,
       compile_data *, int *);
   
   
   
 /*************************************************  /*************************************************
 *      Code parameters and static tables         *  *      Code parameters and static tables         *
 *************************************************/  *************************************************/
Line 99  kicks in at the same number of forward references in a Line 115  kicks in at the same number of forward references in a
 #define COMPILE_WORK_SIZE (2048*LINK_SIZE)  #define COMPILE_WORK_SIZE (2048*LINK_SIZE)
 #define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE)  #define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE)
   
   /* This value determines the size of the initial vector that is used for
   remembering named groups during the pre-compile. It is allocated on the stack,
   but if it is too small, it is expanded using malloc(), in a similar way to the
   workspace. The value is the number of slots in the list. */
   
   #define NAMED_GROUP_LIST_SIZE  20
   
 /* The overrun tests check for a slightly smaller size so that they detect the  /* The overrun tests check for a slightly smaller size so that they detect the
 overrun before it actually does run off the end of the data block. */  overrun before it actually does run off the end of the data block. */
   
 #define WORK_SIZE_SAFETY_MARGIN (100)  #define WORK_SIZE_SAFETY_MARGIN (100)
   
   /* Private flags added to firstchar and reqchar. */
   
   #define REQ_CASELESS    (1 << 0)        /* Indicates caselessness */
   #define REQ_VARY        (1 << 1)        /* Reqchar followed non-literal item */
   /* Negative values for the firstchar and reqchar flags */
   #define REQ_UNSET       (-2)
   #define REQ_NONE        (-1)
   
   /* Repeated character flags. */
   
   #define UTF_LENGTH     0x10000000l      /* The char contains its length. */
   
 /* Table for handling escaped characters in the range '0'-'z'. Positive returns  /* Table for handling escaped characters in the range '0'-'z'. Positive returns
 are simple data values; negative values are for special things like \d and so  are simple data values; negative values are for special things like \d and so
 on. Zero means further processing is needed (for things like \x), or the escape  on. Zero means further processing is needed (for things like \x), or the escape
Line 226  static const verbitem verbs[] = { Line 260  static const verbitem verbs[] = {
 static const int verbcount = sizeof(verbs)/sizeof(verbitem);  static const int verbcount = sizeof(verbs)/sizeof(verbitem);
   
   
   /* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in
   another regex library. */
   
   static const pcre_uchar sub_start_of_word[] = {
     CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
     CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' };
   
   static const pcre_uchar sub_end_of_word[] = {
     CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
     CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w,
     CHAR_RIGHT_PARENTHESIS, '\0' };
   
   
 /* Tables of names of POSIX character classes and their lengths. The names are  /* Tables of names of POSIX character classes and their lengths. The names are
 now all in a single string, to reduce the number of relocations when a shared  now all in a single string, to reduce the number of relocations when a shared
 library is dynamically loaded. The list of lengths is terminated by a zero  library is dynamically loaded. The list of lengths is terminated by a zero
 length entry. The first three must be alpha, lower, upper, as this is assumed  length entry. The first three must be alpha, lower, upper, as this is assumed
for handling case independence. */for handling case independence. The indices for graph, print, and punct are
 needed, so identify them. */
   
 static const char posix_names[] =  static const char posix_names[] =
   STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0    STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0
Line 238  static const char posix_names[] = Line 286  static const char posix_names[] =
   STRING_graph0 STRING_print0 STRING_punct0 STRING_space0    STRING_graph0 STRING_print0 STRING_punct0 STRING_space0
   STRING_word0  STRING_xdigit;    STRING_word0  STRING_xdigit;
   
static const uschar posix_name_lengths[] = {static const pcre_uint8 posix_name_lengths[] = {
   5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
   
   #define PC_GRAPH  8
   #define PC_PRINT  9
   #define PC_PUNCT 10
   
   
 /* Table of class bit maps for each POSIX class. Each class is formed from a  /* Table of class bit maps for each POSIX class. Each class is formed from a
 base map, with an optional addition or removal of another map. Then, for some  base map, with an optional addition or removal of another map. Then, for some
 classes, there is some additional tweaking: for [:blank:] the vertical space  classes, there is some additional tweaking: for [:blank:] the vertical space
Line 268  static const int posix_class_maps[] = { Line 321  static const int posix_class_maps[] = {
   cbit_xdigit,-1,          0              /* xdigit */    cbit_xdigit,-1,          0              /* xdigit */
 };  };
   
/* Table of substitutes for \d etc when PCRE_UCP is set. The POSIX class/* Table of substitutes for \d etc when PCRE_UCP is set. They are replaced by
substitutes must be in the order of the names, defined above, and there areUnicode property escapes. */
both positive and negative cases. NULL means no substitute. */ 
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
static const uschar *substitutes[] = {static const pcre_uchar string_PNd[]  = {
  (uschar *)"\\P{Nd}",    /* \D */  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
  (uschar *)"\\p{Nd}",    /* \d */  CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\P{Xsp}",   /* \S */       /* NOTE: Xsp is Perl space */static const pcre_uchar string_pNd[]  = {
  (uschar *)"\\p{Xsp}",   /* \s */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  (uschar *)"\\P{Xwd}",   /* \W */  CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\p{Xwd}"    /* \w */static const pcre_uchar string_PXsp[] = {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_pXsp[] = {
   CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_PXwd[] = {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_pXwd[] = {
   CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 
 static const pcre_uchar *substitutes[] = {
   string_PNd,           /* \D */
   string_pNd,           /* \d */
   string_PXsp,          /* \S */   /* Xsp is Perl space, but from 8.34, Perl */
   string_pXsp,          /* \s */   /* space and POSIX space are the same. */
   string_PXwd,          /* \W */
   string_pXwd           /* \w */
 };  };
   
static const uschar *posix_substitutes[] = {/* The POSIX class substitutes must be in the order of the POSIX class names,
  (uschar *)"\\p{L}",     /* alpha */defined above, and there are both positive and negative cases. NULL means no
  (uschar *)"\\p{Ll}",    /* lower */general substitute of a Unicode property escape (\p or \P). However, for some
  (uschar *)"\\p{Lu}",    /* upper */POSIX classes (e.g. graph, print, punct) a special property code is compiled
  (uschar *)"\\p{Xan}",   /* alnum */directly. */
  NULL,                   /* ascii */
  (uschar *)"\\h",        /* blank */static const pcre_uchar string_pL[] =   {
  NULL,                   /* cntrl */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  (uschar *)"\\p{Nd}",    /* digit */  CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  NULL,                   /* graph */static const pcre_uchar string_pLl[] =  {
  NULL,                   /* print */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  NULL,                   /* punct */  CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\p{Xps}",   /* space */    /* NOTE: Xps is POSIX space */static const pcre_uchar string_pLu[] =  {
  (uschar *)"\\p{Xwd}",   /* word */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  NULL,                   /* xdigit */  CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_pXan[] = {
   CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_h[] =    {
   CHAR_BACKSLASH, CHAR_h, '\0' };
 static const pcre_uchar string_pXps[] = {
   CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_PL[] =   {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_PLl[] =  {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_PLu[] =  {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_PXan[] = {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 static const pcre_uchar string_H[] =    {
   CHAR_BACKSLASH, CHAR_H, '\0' };
 static const pcre_uchar string_PXps[] = {
   CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
   CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
 
 static const pcre_uchar *posix_substitutes[] = {
   string_pL,            /* alpha */
   string_pLl,           /* lower */
   string_pLu,           /* upper */
   string_pXan,          /* alnum */
   NULL,                 /* ascii */
   string_h,             /* blank */
   NULL,                 /* cntrl */
   string_pNd,           /* digit */
   NULL,                 /* graph */
   NULL,                 /* print */
   NULL,                 /* punct */
   string_pXps,          /* space */   /* Xps is POSIX space, but from 8.34 */
   string_pXwd,          /* word  */   /* Perl and POSIX space are the same */
   NULL,                 /* xdigit */
   /* Negated cases */    /* Negated cases */
  (uschar *)"\\P{L}",     /* ^alpha */  string_PL,            /* ^alpha */
  (uschar *)"\\P{Ll}",    /* ^lower */  string_PLl,           /* ^lower */
  (uschar *)"\\P{Lu}",    /* ^upper */  string_PLu,           /* ^upper */
  (uschar *)"\\P{Xan}",   /* ^alnum */  string_PXan,          /* ^alnum */
  NULL,                   /* ^ascii */  NULL,                 /* ^ascii */
  (uschar *)"\\H",        /* ^blank */  string_H,             /* ^blank */
  NULL,                   /* ^cntrl */  NULL,                 /* ^cntrl */
  (uschar *)"\\P{Nd}",    /* ^digit */  string_PNd,           /* ^digit */
  NULL,                   /* ^graph */  NULL,                 /* ^graph */
  NULL,                   /* ^print */  NULL,                 /* ^print */
  NULL,                   /* ^punct */  NULL,                 /* ^punct */
  (uschar *)"\\P{Xps}",   /* ^space */   /* NOTE: Xps is POSIX space */  string_PXps,          /* ^space */  /* Xps is POSIX space, but from 8.34 */
  (uschar *)"\\P{Xwd}",   /* ^word */  string_PXwd,          /* ^word */   /* Perl and POSIX space are the same */
  NULL                    /* ^xdigit */  NULL                  /* ^xdigit */
 };  };
#define POSIX_SUBSIZE (sizeof(posix_substitutes)/sizeof(uschar *))#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(pcre_uchar *))
 #endif  #endif
   
 #define STRING(a)  # a  #define STRING(a)  # a
Line 372  static const char error_texts[] = Line 484  static const char error_texts[] =
   /* 30 */    /* 30 */
   "unknown POSIX class name\0"    "unknown POSIX class name\0"
   "POSIX collating elements are not supported\0"    "POSIX collating elements are not supported\0"
  "this version of PCRE is not compiled with PCRE_UTF8 support\0"  "this version of PCRE is compiled without UTF support\0"
   "spare error\0"  /** DEAD **/    "spare error\0"  /** DEAD **/
  "character value in \\x{...} sequence is too large\0"  "character value in \\x{} or \\o{} is too large\0"
   /* 35 */    /* 35 */
   "invalid condition (?(0)\0"    "invalid condition (?(0)\0"
   "\\C not allowed in lookbehind assertion\0"    "\\C not allowed in lookbehind assertion\0"
Line 395  static const char error_texts[] = Line 507  static const char error_texts[] =
   "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"    "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"
   /* 50 */    /* 50 */
   "repeated subpattern is too long\0"    /** DEAD **/    "repeated subpattern is too long\0"    /** DEAD **/
  "octal value is greater than \\377 (not in UTF-8 mode)\0"  "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0"
   "internal error: overran compiling workspace\0"    "internal error: overran compiling workspace\0"
   "internal error: previously-checked referenced subpattern not found\0"    "internal error: previously-checked referenced subpattern not found\0"
   "DEFINE group contains more than one branch\0"    "DEFINE group contains more than one branch\0"
Line 406  static const char error_texts[] = Line 518  static const char error_texts[] =
   "a numbered reference must not be zero\0"    "a numbered reference must not be zero\0"
   "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"    "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"
   /* 60 */    /* 60 */
  "(*VERB) not recognized\0"  "(*VERB) not recognized or malformed\0"
   "number is too big\0"    "number is too big\0"
   "subpattern name expected\0"    "subpattern name expected\0"
   "digit expected after (?+\0"    "digit expected after (?+\0"
Line 414  static const char error_texts[] = Line 526  static const char error_texts[] =
   /* 65 */    /* 65 */
   "different names for subpatterns of the same number are not allowed\0"    "different names for subpatterns of the same number are not allowed\0"
   "(*MARK) must have an argument\0"    "(*MARK) must have an argument\0"
  "this version of PCRE is not compiled with PCRE_UCP support\0"  "this version of PCRE is not compiled with Unicode property support\0"
   "\\c must be followed by an ASCII character\0"    "\\c must be followed by an ASCII character\0"
   "\\k is not followed by a braced, angle-bracketed, or quoted name\0"    "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
   /* 70 */    /* 70 */
   "internal error: unknown opcode in find_fixedlength()\0"    "internal error: unknown opcode in find_fixedlength()\0"
   "\\N is not supported in a class\0"    "\\N is not supported in a class\0"
   "too many forward references\0"    "too many forward references\0"
     "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
     "invalid UTF-16 string\0"
     /* 75 */
     "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
     "character value in \\u.... sequence is too large\0"
     "invalid UTF-32 string\0"
     "setting UTF is disabled by the application\0"
     "non-hex character in \\x{} (closing brace missing?)\0"
     /* 80 */
     "non-octal character in \\o{} (closing brace missing?)\0"
     "missing opening brace after \\o\0"
     "parentheses are too deeply nested\0"
     "invalid range in character class\0"
     "group name must start with a non-digit\0"
   ;    ;
   
 /* Table to identify digits and hex digits. This is used when compiling  /* Table to identify digits and hex digits. This is used when compiling
Line 439  For convenience, we use the same bit definitions as in Line 565  For convenience, we use the same bit definitions as in
   
 Then we can use ctype_digit and ctype_xdigit in the code. */  Then we can use ctype_digit and ctype_xdigit in the code. */
   
   /* Using a simple comparison for decimal numbers rather than a memory read
   is much faster, and the resulting code is simpler (the compiler turns it
   into a subtraction and unsigned comparison). */
   
   #define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9)
   
 #ifndef EBCDIC  #ifndef EBCDIC
   
 /* This is the "normal" case, for ASCII systems, and EBCDIC systems running in  /* This is the "normal" case, for ASCII systems, and EBCDIC systems running in
 UTF-8 mode. */  UTF-8 mode. */
   
static const unsigned char digitab[] =static const pcre_uint8 digitab[] =
   {    {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15 */    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15 */
Line 483  static const unsigned char digitab[] = Line 615  static const unsigned char digitab[] =
   
 /* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */  /* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */
   
static const unsigned char digitab[] =static const pcre_uint8 digitab[] =
   {    {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7  0 */    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7  0 */
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15    */    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15    */
Line 518  static const unsigned char digitab[] = Line 650  static const unsigned char digitab[] =
   0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /*  0 - 7  F0 */    0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /*  0 - 7  F0 */
   0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/*  8 -255    */    0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/*  8 -255    */
   
static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */static const pcre_uint8 ebcdic_chartab[] = { /* chartable partial dup */
   0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*   0-  7 */    0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*   0-  7 */
   0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /*   8- 15 */    0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /*   8- 15 */
   0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*  16- 23 */    0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*  16- 23 */
Line 554  static const unsigned char ebcdic_chartab[] = { /* cha Line 686  static const unsigned char ebcdic_chartab[] = { /* cha
 #endif  #endif
   
   
/* Definition to allow mutual recursion *//* This table is used to check whether auto-possessification is possible
 between adjacent character-type opcodes. The left-hand (repeated) opcode is
 used to select the row, and the right-hand opcode is use to select the column.
 A value of 1 means that auto-possessification is OK. For example, the second
 value in the first row means that \D+\d can be turned into \D++\d.
   
static BOOLThe Unicode property types (\P and \p) have to be present to fill out the table
  compile_regex(int, uschar **, const uschar **, int *, BOOL, BOOL, int, int,because of what their opcode values are, but the table values should always be
    int *, int *, branch_chain *, compile_data *, int *);zero because property types are handled separately in the code. The last four
 columns apply to items that cannot be repeated, so there is no need to have
 rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is
 *not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
   
   #define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1)
   #define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1)
   
   static const pcre_uint8 autoposstab[APTROWS][APTCOLS] = {
   /* \D \d \S \s \W \w  . .+ \C \P \p \R \H \h \V \v \X \Z \z  $ $M */
     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \D */
     { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \d */
     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \S */
     { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \s */
     { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \W */
     { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \w */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* .  */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* .+ */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \C */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* \P */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* \p */
     { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 },  /* \R */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 },  /* \H */
     { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 },  /* \h */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 },  /* \V */
     { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 },  /* \v */
     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }   /* \X */
   };
   
   
   /* This table is used to check whether auto-possessification is possible
   between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The
   left-hand (repeated) opcode is used to select the row, and the right-hand
   opcode is used to select the column. The values are as follows:
   
     0   Always return FALSE (never auto-possessify)
     1   Character groups are distinct (possessify if both are OP_PROP)
     2   Check character categories in the same group (general or particular)
     3   TRUE if the two opcodes are not the same (PROP vs NOTPROP)
   
     4   Check left general category vs right particular category
     5   Check right general category vs left particular category
   
     6   Left alphanum vs right general category
     7   Left space vs right general category
     8   Left word vs right general category
   
     9   Right alphanum vs left general category
    10   Right space vs left general category
    11   Right word vs left general category
   
    12   Left alphanum vs right particular category
    13   Left space vs right particular category
    14   Left word vs right particular category
   
    15   Right alphanum vs left particular category
    16   Right space vs left particular category
    17   Right word vs left particular category
   */
   
   static const pcre_uint8 propposstab[PT_TABSIZE][PT_TABSIZE] = {
   /* ANY LAMP GC  PC  SC ALNUM SPACE PXSPACE WORD CLIST UCNC */
     { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   0 },  /* PT_ANY */
     { 0,  3,  0,  0,  0,    3,    1,      1,   0,    0,   0 },  /* PT_LAMP */
     { 0,  0,  2,  4,  0,    9,   10,     10,  11,    0,   0 },  /* PT_GC */
     { 0,  0,  5,  2,  0,   15,   16,     16,  17,    0,   0 },  /* PT_PC */
     { 0,  0,  0,  0,  2,    0,    0,      0,   0,    0,   0 },  /* PT_SC */
     { 0,  3,  6, 12,  0,    3,    1,      1,   0,    0,   0 },  /* PT_ALNUM */
     { 0,  1,  7, 13,  0,    1,    3,      3,   1,    0,   0 },  /* PT_SPACE */
     { 0,  1,  7, 13,  0,    1,    3,      3,   1,    0,   0 },  /* PT_PXSPACE */
     { 0,  0,  8, 14,  0,    0,    1,      1,   3,    0,   0 },  /* PT_WORD */
     { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   0 },  /* PT_CLIST */
     { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   3 }   /* PT_UCNC */
   };
   
   /* This table is used to check whether auto-possessification is possible
   between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one
   specifies a general category and the other specifies a particular category. The
   row is selected by the general category and the column by the particular
   category. The value is 1 if the particular category is not part of the general
   category. */
   
   static const pcre_uint8 catposstab[7][30] = {
   /* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */
     { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* C */
     { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* L */
     { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* M */
     { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* N */
     { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 },  /* P */
     { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 },  /* S */
     { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }   /* Z */
   };
   
   /* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against
   a general or particular category. The properties in each row are those
   that apply to the character set in question. Duplication means that a little
   unnecessary work is done when checking, but this keeps things much simpler
   because they can all use the same code. For more details see the comment where
   this table is used.
   
   Note: SPACE and PXSPACE used to be different because Perl excluded VT from
   "space", but from Perl 5.18 it's included, so both categories are treated the
   same here. */
   
   static const pcre_uint8 posspropstab[3][4] = {
     { ucp_L, ucp_N, ucp_N, ucp_Nl },  /* ALNUM, 3rd and 4th values redundant */
     { ucp_Z, ucp_Z, ucp_C, ucp_Cc },  /* SPACE and PXSPACE, 2nd value redundant */
     { ucp_L, ucp_N, ucp_P, ucp_Po }   /* WORD */
   };
   
   /* This table is used when converting repeating opcodes into possessified
   versions as a result of an explicit possessive quantifier such as ++. A zero
   value means there is no possessified version - in those cases the item in
   question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT
   because all relevant opcodes are less than that. */
   
   static const pcre_uint8 opcode_possessify[] = {
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0 - 15  */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 16 - 31 */
   
     0,                       /* NOTI */
     OP_POSSTAR, 0,           /* STAR, MINSTAR */
     OP_POSPLUS, 0,           /* PLUS, MINPLUS */
     OP_POSQUERY, 0,          /* QUERY, MINQUERY */
     OP_POSUPTO, 0,           /* UPTO, MINUPTO */
     0,                       /* EXACT */
     0, 0, 0, 0,              /* POS{STAR,PLUS,QUERY,UPTO} */
   
     OP_POSSTARI, 0,          /* STARI, MINSTARI */
     OP_POSPLUSI, 0,          /* PLUSI, MINPLUSI */
     OP_POSQUERYI, 0,         /* QUERYI, MINQUERYI */
     OP_POSUPTOI, 0,          /* UPTOI, MINUPTOI */
     0,                       /* EXACTI */
     0, 0, 0, 0,              /* POS{STARI,PLUSI,QUERYI,UPTOI} */
   
     OP_NOTPOSSTAR, 0,        /* NOTSTAR, NOTMINSTAR */
     OP_NOTPOSPLUS, 0,        /* NOTPLUS, NOTMINPLUS */
     OP_NOTPOSQUERY, 0,       /* NOTQUERY, NOTMINQUERY */
     OP_NOTPOSUPTO, 0,        /* NOTUPTO, NOTMINUPTO */
     0,                       /* NOTEXACT */
     0, 0, 0, 0,              /* NOTPOS{STAR,PLUS,QUERY,UPTO} */
   
     OP_NOTPOSSTARI, 0,       /* NOTSTARI, NOTMINSTARI */
     OP_NOTPOSPLUSI, 0,       /* NOTPLUSI, NOTMINPLUSI */
     OP_NOTPOSQUERYI, 0,      /* NOTQUERYI, NOTMINQUERYI */
     OP_NOTPOSUPTOI, 0,       /* NOTUPTOI, NOTMINUPTOI */
     0,                       /* NOTEXACTI */
     0, 0, 0, 0,              /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */
   
     OP_TYPEPOSSTAR, 0,       /* TYPESTAR, TYPEMINSTAR */
     OP_TYPEPOSPLUS, 0,       /* TYPEPLUS, TYPEMINPLUS */
     OP_TYPEPOSQUERY, 0,      /* TYPEQUERY, TYPEMINQUERY */
     OP_TYPEPOSUPTO, 0,       /* TYPEUPTO, TYPEMINUPTO */
     0,                       /* TYPEEXACT */
     0, 0, 0, 0,              /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */
   
     OP_CRPOSSTAR, 0,         /* CRSTAR, CRMINSTAR */
     OP_CRPOSPLUS, 0,         /* CRPLUS, CRMINPLUS */
     OP_CRPOSQUERY, 0,        /* CRQUERY, CRMINQUERY */
     OP_CRPOSRANGE, 0,        /* CRRANGE, CRMINRANGE */
     0, 0, 0, 0,              /* CRPOS{STAR,PLUS,QUERY,RANGE} */
   
     0, 0, 0,                 /* CLASS, NCLASS, XCLASS */
     0, 0,                    /* REF, REFI */
     0, 0,                    /* DNREF, DNREFI */
     0, 0                     /* RECURSE, CALLOUT */
   };
   
   
   
 /*************************************************  /*************************************************
 *            Find an error text                  *  *            Find an error text                  *
 *************************************************/  *************************************************/
Line 581  find_error_text(int n) Line 883  find_error_text(int n)
 const char *s = error_texts;  const char *s = error_texts;
 for (; n > 0; n--)  for (; n > 0; n--)
   {    {
  while (*s++ != 0) {};  while (*s++ != CHAR_NULL) {};
  if (*s == 0) return "Error text not found (please report)";  if (*s == CHAR_NULL) return "Error text not found (please report)";
   }    }
 return s;  return s;
 }  }
   
   
   
 /*************************************************  /*************************************************
 *           Expand the workspace                 *  *           Expand the workspace                 *
 *************************************************/  *************************************************/
Line 604  Returns:  0 if all went well, else an error number Line 907  Returns:  0 if all went well, else an error number
 static int  static int
 expand_workspace(compile_data *cd)  expand_workspace(compile_data *cd)
 {  {
uschar *newspace;pcre_uchar *newspace;
 int newsize = cd->workspace_size * 2;  int newsize = cd->workspace_size * 2;
   
 if (newsize > COMPILE_WORK_SIZE_MAX) newsize = COMPILE_WORK_SIZE_MAX;  if (newsize > COMPILE_WORK_SIZE_MAX) newsize = COMPILE_WORK_SIZE_MAX;
Line 612  if (cd->workspace_size >= COMPILE_WORK_SIZE_MAX || Line 915  if (cd->workspace_size >= COMPILE_WORK_SIZE_MAX ||
     newsize - cd->workspace_size < WORK_SIZE_SAFETY_MARGIN)      newsize - cd->workspace_size < WORK_SIZE_SAFETY_MARGIN)
  return ERR72;   return ERR72;
   
newspace = (pcre_malloc)(newsize);newspace = (PUBL(malloc))(IN_UCHARS(newsize));
 if (newspace == NULL) return ERR21;  if (newspace == NULL) return ERR21;
memcpy(newspace, cd->start_workspace, cd->workspace_size * sizeof(pcre_uchar));
memcpy(newspace, cd->start_workspace, cd->workspace_size);cd->hwm = (pcre_uchar *)newspace + (cd->hwm - cd->start_workspace);
cd->hwm = (uschar *)newspace + (cd->hwm - cd->start_workspace); 
 if (cd->workspace_size > COMPILE_WORK_SIZE)  if (cd->workspace_size > COMPILE_WORK_SIZE)
  (pcre_free)((void *)cd->start_workspace);  (PUBL(free))((void *)cd->start_workspace);
 cd->start_workspace = newspace;  cd->start_workspace = newspace;
 cd->workspace_size = newsize;  cd->workspace_size = newsize;
 return 0;  return 0;
Line 642  Returns:    TRUE or FALSE Line 944  Returns:    TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
is_counted_repeat(const uschar *p)is_counted_repeat(const pcre_uchar *p)
 {  {
if ((digitab[*p++] & ctype_digit) == 0) return FALSE;if (!IS_DIGIT(*p)) return FALSE;
while ((digitab[*p] & ctype_digit) != 0) p++;p++;
 while (IS_DIGIT(*p)) p++;
 if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;  if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
   
 if (*p++ != CHAR_COMMA) return FALSE;  if (*p++ != CHAR_COMMA) return FALSE;
 if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;  if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
   
if ((digitab[*p++] & ctype_digit) == 0) return FALSE;if (!IS_DIGIT(*p)) return FALSE;
while ((digitab[*p] & ctype_digit) != 0) p++;p++;
 while (IS_DIGIT(*p)) p++;
   
 return (*p == CHAR_RIGHT_CURLY_BRACKET);  return (*p == CHAR_RIGHT_CURLY_BRACKET);
 }  }
Line 664  return (*p == CHAR_RIGHT_CURLY_BRACKET); Line 968  return (*p == CHAR_RIGHT_CURLY_BRACKET);
 *************************************************/  *************************************************/
   
 /* This function is called when a \ has been encountered. It either returns a  /* This function is called when a \ has been encountered. It either returns a
positive value for a simple escape such as \n, or a negative value whichpositive value for a simple escape such as \n, or 0 for a data character which
encodes one of the more complicated things such as \d. A backreference to groupwill be placed in chptr. A backreference to group n is returned as negative n.
n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. WhenWhen UTF-8 is enabled, a positive value greater than 255 may be returned in
UTF-8 is enabled, a positive value greater than 255 may be returned. On entry,chptr. On entry, ptr is pointing at the \. On exit, it is on the final
ptr is pointing at the \. On exit, it is on the final character of the escapecharacter of the escape sequence.
sequence. 
   
 Arguments:  Arguments:
   ptrptr         points to the pattern position pointer    ptrptr         points to the pattern position pointer
     chptr          points to a returned data character
   errorcodeptr   points to the errorcode variable    errorcodeptr   points to the errorcode variable
   bracount       number of previous extracting brackets    bracount       number of previous extracting brackets
   options        the options bits    options        the options bits
   isclass        TRUE if inside a character class    isclass        TRUE if inside a character class
   
Returns:         zero or positive => a data characterReturns:         zero => a data character
                 negative => a special escape sequence                 positive => a special escape sequence
                  negative => a back reference
                  on error, errorcodeptr is set                   on error, errorcodeptr is set
 */  */
   
 static int  static int
check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount,check_escape(const pcre_uchar **ptrptr, pcre_uint32 *chptr, int *errorcodeptr,
  int options, BOOL isclass)  int bracount, int options, BOOL isclass)
 {  {
BOOL utf8 = (options & PCRE_UTF8) != 0;/* PCRE_UTF16 has the same value as PCRE_UTF8. */
const uschar *ptr = *ptrptr + 1;BOOL utf = (options & PCRE_UTF8) != 0;
int c, i;const pcre_uchar *ptr = *ptrptr + 1;
 pcre_uint32 c;
 int escape = 0;
 int i;
   
 GETCHARINCTEST(c, ptr);           /* Get character value, increment pointer */  GETCHARINCTEST(c, ptr);           /* Get character value, increment pointer */
 ptr--;                            /* Set pointer back to the last byte */  ptr--;                            /* Set pointer back to the last byte */
   
 /* If backslash is at the end of the pattern, it's an error. */  /* If backslash is at the end of the pattern, it's an error. */
   
if (c == 0) *errorcodeptr = ERR1;if (c == CHAR_NULL) *errorcodeptr = ERR1;
   
 /* Non-alphanumerics are literals. For digits or letters, do an initial lookup  /* Non-alphanumerics are literals. For digits or letters, do an initial lookup
 in a table. A non-zero result is something that can be returned immediately.  in a table. A non-zero result is something that can be returned immediately.
 Otherwise further processing may be required. */  Otherwise further processing may be required. */
   
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
else if (c < CHAR_0 || c > CHAR_z) {}                     /* Not alphanumeric *//* Not alphanumeric */
else if ((i = escapes[c - CHAR_0]) != 0) c = i;else if (c < CHAR_0 || c > CHAR_z) {}
 else if ((i = escapes[c - CHAR_0]) != 0)
   { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
   
 #else           /* EBCDIC coding */  #else           /* EBCDIC coding */
else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {}   /* Not alphanumeric *//* Not alphanumeric */
else if ((i = escapes[c - 0x48]) != 0)  c = i;else if (c < CHAR_a || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {}
 else if ((i = escapes[c - 0x48]) != 0)  { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
 #endif  #endif
   
 /* Escapes that need further processing, or are illegal. */  /* Escapes that need further processing, or are illegal. */
   
 else  else
   {    {
  const uschar *oldptr;  const pcre_uchar *oldptr;
  BOOL braced, negated;  BOOL braced, negated, overflow;
   int s;
   
   switch (c)    switch (c)
     {      {
Line 733  else Line 1045  else
       {        {
       /* In JavaScript, \u must be followed by four hexadecimal numbers.        /* In JavaScript, \u must be followed by four hexadecimal numbers.
       Otherwise it is a lowercase u letter. */        Otherwise it is a lowercase u letter. */
      if ((digitab[ptr[1]] & ctype_xdigit) != 0 && (digitab[ptr[2]] & ctype_xdigit) != 0      if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0
           && (digitab[ptr[3]] & ctype_xdigit) != 0 && (digitab[ptr[4]] & ctype_xdigit) != 0)        && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0
         && MAX_255(ptr[3]) && (digitab[ptr[3]] & ctype_xdigit) != 0
         && MAX_255(ptr[4]) && (digitab[ptr[4]] & ctype_xdigit) != 0)
         {          {
         c = 0;          c = 0;
         for (i = 0; i < 4; ++i)          for (i = 0; i < 4; ++i)
           {            {
          register int cc = *(++ptr);          register pcre_uint32 cc = *(++ptr);
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
           if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */            if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
           c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));            c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
Line 748  else Line 1062  else
           c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));            c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
 #endif  #endif
           }            }
   
   #if defined COMPILE_PCRE8
           if (c > (utf ? 0x10ffffU : 0xffU))
   #elif defined COMPILE_PCRE16
           if (c > (utf ? 0x10ffffU : 0xffffU))
   #elif defined COMPILE_PCRE32
           if (utf && c > 0x10ffffU)
   #endif
             {
             *errorcodeptr = ERR76;
             }
           else if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
         }          }
       }        }
     else      else
Line 774  else Line 1100  else
     (3) For Oniguruma compatibility we also support \g followed by a name or a      (3) For Oniguruma compatibility we also support \g followed by a name or a
     number either in angle brackets or in single quotes. However, these are      number either in angle brackets or in single quotes. However, these are
     (possibly recursive) subroutine calls, _not_ backreferences. Just return      (possibly recursive) subroutine calls, _not_ backreferences. Just return
    the -ESC_g code (cf \k). */    the ESC_g code (cf \k). */
   
     case CHAR_g:      case CHAR_g:
     if (isclass) break;      if (isclass) break;
     if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)      if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)
       {        {
      c = -ESC_g;      escape = ESC_g;
       break;        break;
       }        }
   
Line 788  else Line 1114  else
   
     if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)      if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
       {        {
      const uschar *p;      const pcre_uchar *p;
      for (p = ptr+2; *p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET; p++)      for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++)
        if (*p != CHAR_MINUS && (digitab[*p] & ctype_digit) == 0) break;        if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;
      if (*p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET)      if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET)
         {          {
        c = -ESC_k;        escape = ESC_k;
         break;          break;
         }          }
       braced = TRUE;        braced = TRUE;
Line 808  else Line 1134  else
       }        }
     else negated = FALSE;      else negated = FALSE;
   
    c = 0;    /* The integer range is limited by the machine's int representation. */
    while ((digitab[ptr[1]] & ctype_digit) != 0)    s = 0;
      c = c * 10 + *(++ptr) - CHAR_0;    overflow = FALSE;
    while (IS_DIGIT(ptr[1]))
    if (c < 0)   /* Integer overflow */ 
       {        {
         if (s > INT_MAX / 10 - 1) /* Integer overflow */
           {
           overflow = TRUE;
           break;
           }
         s = s * 10 + (int)(*(++ptr) - CHAR_0);
         }
       if (overflow) /* Integer overflow */
         {
         while (IS_DIGIT(ptr[1]))
           ptr++;
       *errorcodeptr = ERR61;        *errorcodeptr = ERR61;
       break;        break;
       }        }
Line 824  else Line 1160  else
       break;        break;
       }        }
   
    if (c == 0)    if (s == 0)
       {        {
       *errorcodeptr = ERR58;        *errorcodeptr = ERR58;
       break;        break;
Line 832  else Line 1168  else
   
     if (negated)      if (negated)
       {        {
      if (c > bracount)      if (s > bracount)
         {          {
         *errorcodeptr = ERR15;          *errorcodeptr = ERR15;
         break;          break;
         }          }
      c = bracount - (c - 1);      s = bracount - (s - 1);
       }        }
   
    c = -(ESC_REF + c);    escape = -s;
     break;      break;
   
     /* The handling of escape sequences consisting of a string of digits      /* The handling of escape sequences consisting of a string of digits
    starting with one that is not zero is not straightforward. By experiment,    starting with one that is not zero is not straightforward. Perl has changed
    the way Perl works seems to be as follows:    over the years. Nowadays \g{} for backreferences and \o{} for octal are
     recommended to avoid the ambiguities in the old syntax.
   
     Outside a character class, the digits are read as a decimal number. If the      Outside a character class, the digits are read as a decimal number. If the
    number is less than 10, or if there are that many previous extracting    number is less than 8 (used to be 10), or if there are that many previous
    left brackets, then it is a back reference. Otherwise, up to three octal    extracting left brackets, then it is a back reference. Otherwise, up to
    digits are read to form an escaped byte. Thus \123 is likely to be octal    three octal digits are read to form an escaped byte. Thus \123 is likely to
    123 (cf \0123, which is octal 012 followed by the literal 3). If the octal    be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If
    value is greater than 377, the least significant 8 bits are taken. Inside a    the octal value is greater than 377, the least significant 8 bits are
    character class, \ followed by a digit is always an octal number. */    taken. \8 and \9 are treated as the literal characters 8 and 9.
   
       Inside a character class, \ followed by a digit is always either a literal
       8 or 9 or an octal number. */
   
     case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:      case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:
     case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:      case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
   
     if (!isclass)      if (!isclass)
       {        {
       oldptr = ptr;        oldptr = ptr;
      c -= CHAR_0;      /* The integer range is limited by the machine's int representation. */
      while ((digitab[ptr[1]] & ctype_digit) != 0)      s = (int)(c -CHAR_0);
        c = c * 10 + *(++ptr) - CHAR_0;      overflow = FALSE;
      if (c < 0)    /* Integer overflow */      while (IS_DIGIT(ptr[1]))
         {          {
           if (s > INT_MAX / 10 - 1) /* Integer overflow */
             {
             overflow = TRUE;
             break;
             }
           s = s * 10 + (int)(*(++ptr) - CHAR_0);
           }
         if (overflow) /* Integer overflow */
           {
           while (IS_DIGIT(ptr[1]))
             ptr++;
         *errorcodeptr = ERR61;          *errorcodeptr = ERR61;
         break;          break;
         }          }
      if (c < 10 || c <= bracount)      if (s < 8 || s <= bracount)  /* Check for back reference */
         {          {
        c = -(ESC_REF + c);        escape = -s;
         break;          break;
         }          }
       ptr = oldptr;      /* Put the pointer back and fall through */        ptr = oldptr;      /* Put the pointer back and fall through */
       }        }
   
    /* Handle an octal number following \. If the first digit is 8 or 9, Perl    /* Handle a digit following \ when the number is not a back reference. If
    generates a binary zero byte and treats the digit as a following literal.    the first digit is 8 or 9, Perl used to generate a binary zero byte and
    Thus we have to pull back the pointer by one. */    then treat the digit as a following literal. At least by Perl 5.18 this
     changed so as not to insert the binary zero. */
   
    if ((c = *ptr) >= CHAR_8)    if ((c = *ptr) >= CHAR_8) break;
      { 
      ptr--; 
      c = 0; 
      break; 
      } 
   
       /* Fall through with a digit less than 8 */
   
     /* \0 always starts an octal number, but we may drop through to here with a      /* \0 always starts an octal number, but we may drop through to here with a
     larger first octal digit. The original code used just to take the least      larger first octal digit. The original code used just to take the least
     significant 8 bits of octal numbers (I think this is what early Perls used      significant 8 bits of octal numbers (I think this is what early Perls used
    to do). Nowadays we allow for larger numbers in UTF-8 mode, but no more    to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode,
    than 3 octal digits. */    but no more than 3 octal digits. */
   
     case CHAR_0:      case CHAR_0:
     c -= CHAR_0;      c -= CHAR_0;
     while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7)      while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7)
         c = c * 8 + *(++ptr) - CHAR_0;          c = c * 8 + *(++ptr) - CHAR_0;
    if (!utf8 && c > 255) *errorcodeptr = ERR51;#ifdef COMPILE_PCRE8
     if (!utf && c > 0xff) *errorcodeptr = ERR51;
 #endif
     break;      break;
   
    /* \x is complicated. \x{ddd} is a character number which can be greater    /* \o is a relatively new Perl feature, supporting a more general way of
    than 0xff in utf8 mode, but only if the ddd are hex digits. If not, { is    specifying character codes in octal. The only supported form is \o{ddd}. */
    treated as a data character. */ 
   
       case CHAR_o:
       if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR81; else
         {
         ptr += 2;
         c = 0;
         overflow = FALSE;
         while (*ptr >= CHAR_0 && *ptr <= CHAR_7)
           {
           register pcre_uint32 cc = *ptr++;
           if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
   #ifdef COMPILE_PCRE32
           if (c >= 0x20000000l) { overflow = TRUE; break; }
   #endif
           c = (c << 3) + cc - CHAR_0 ;
   #if defined COMPILE_PCRE8
           if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
   #elif defined COMPILE_PCRE16
           if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
   #elif defined COMPILE_PCRE32
           if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
   #endif
           }
         if (overflow)
           {
           while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
           *errorcodeptr = ERR34;
           }
         else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
           {
           if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
           }
         else *errorcodeptr = ERR80;
         }
       break;
   
       /* \x is complicated. In JavaScript, \x must be followed by two hexadecimal
       numbers. Otherwise it is a lowercase x letter. */
   
     case CHAR_x:      case CHAR_x:
     if ((options & PCRE_JAVASCRIPT_COMPAT) != 0)      if ((options & PCRE_JAVASCRIPT_COMPAT) != 0)
       {        {
      /* In JavaScript, \x must be followed by two hexadecimal numbers.      if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0
      Otherwise it is a lowercase x letter. */        && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0)
      if ((digitab[ptr[1]] & ctype_xdigit) != 0 && (digitab[ptr[2]] & ctype_xdigit) != 0) 
         {          {
         c = 0;          c = 0;
         for (i = 0; i < 2; ++i)          for (i = 0; i < 2; ++i)
           {            {
          register int cc = *(++ptr);          register pcre_uint32 cc = *(++ptr);
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
           if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */            if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
           c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));            c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
Line 925  else Line 1312  else
 #endif  #endif
           }            }
         }          }
      break;      }    /* End JavaScript handling */
      } 
   
    if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)    /* Handle \x in Perl's style. \x{ddd} is a character number which can be
      {    greater than 0xff in utf or non-8bit mode, but only if the ddd are hex
      const uschar *pt = ptr + 2;    digits. If not, { used to be treated as a data character. However, Perl
      int count = 0;    seems to read hex digits up to the first non-such, and ignore the rest, so
     that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE
     now gives an error. */
   
      c = 0;    else
      while ((digitab[*pt] & ctype_xdigit) != 0)      {
       if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
         {          {
        register int cc = *pt++;        ptr += 2;
        if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */        c = 0;
        count++;        overflow = FALSE;
         while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0)
           {
           register pcre_uint32 cc = *ptr++;
           if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
   
   #ifdef COMPILE_PCRE32
             if (c >= 0x10000000l) { overflow = TRUE; break; }
   #endif
   
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
        if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */          if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
        c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));          c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
 #else           /* EBCDIC coding */  #else           /* EBCDIC coding */
        if (cc >= CHAR_a && cc <= CHAR_z) cc += 64;  /* Convert to upper case */          if (cc >= CHAR_a && cc <= CHAR_z) cc += 64;  /* Convert to upper case */
        c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));          c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
 #endif  #endif
         }  
   
      if (*pt == CHAR_RIGHT_CURLY_BRACKET)#if defined COMPILE_PCRE8
        {          if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
        if (c < 0 || count > (utf8? 8 : 2)) *errorcodeptr = ERR34;#elif defined COMPILE_PCRE16
        ptr = pt;          if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
        break;#elif defined COMPILE_PCRE32
        }          if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
 #endif
           }
   
      /* If the sequence of hex digits does not end with '}', then we don't        if (overflow)
      recognize this construct; fall through to the normal \x handling. */          {
      }          while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) ptr++;
           *errorcodeptr = ERR34;
           }
   
    /* Read just a single-byte hex-defined char */        else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
           {
           if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
           }
   
    c = 0;        /* If the sequence of hex digits does not end with '}', give an error.
    while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0)        We used just to recognize this construct and fall through to the normal
      {        \x handling, but nowadays Perl gives an error, which seems much more
      int cc;                                  /* Some compilers don't like */        sensible, so we do too. */
      cc = *(++ptr);                           /* ++ in initializers */
         else *errorcodeptr = ERR79;
         }   /* End of \x{} processing */
 
       /* Read a single-byte hex-defined char (up to two hex digits after \x) */
 
       else
         {
         c = 0;
         while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0)
           {
           pcre_uint32 cc;                          /* Some compilers don't like */
           cc = *(++ptr);                           /* ++ in initializers */
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
      if (cc >= CHAR_a) cc -= 32;              /* Convert to upper case */          if (cc >= CHAR_a) cc -= 32;              /* Convert to upper case */
      c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));          c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
 #else           /* EBCDIC coding */  #else           /* EBCDIC coding */
      if (cc <= CHAR_z) cc += 64;              /* Convert to upper case */          if (cc <= CHAR_z) cc += 64;              /* Convert to upper case */
      c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));          c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
 #endif  #endif
      }          }
         }     /* End of \xdd handling */
       }       /* End of Perl-style \x handling */
     break;      break;
   
     /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped.      /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped.
Line 984  else Line 1401  else
   
     case CHAR_c:      case CHAR_c:
     c = *(++ptr);      c = *(++ptr);
    if (c == 0)    if (c == CHAR_NULL)
       {        {
       *errorcodeptr = ERR2;        *errorcodeptr = ERR2;
       break;        break;
Line 1024  else Line 1441  else
 newline". PCRE does not support \N{name}. However, it does support  newline". PCRE does not support \N{name}. However, it does support
 quantification such as \N{2,3}. */  quantification such as \N{2,3}. */
   
if (c == -ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&
      !is_counted_repeat(ptr+2))       !is_counted_repeat(ptr+2))
   *errorcodeptr = ERR37;    *errorcodeptr = ERR37;
   
 /* If PCRE_UCP is set, we change the values for \d etc. */  /* If PCRE_UCP is set, we change the values for \d etc. */
   
if ((options & PCRE_UCP) != 0 && c <= -ESC_D && c >= -ESC_w)if ((options & PCRE_UCP) != 0 && escape >= ESC_D && escape <= ESC_w)
  c -= (ESC_DU - ESC_D);  escape += (ESC_DU - ESC_D);
   
 /* Set the pointer to the final character before returning. */  /* Set the pointer to the final character before returning. */
   
 *ptrptr = ptr;  *ptrptr = ptr;
return c;*chptr = c;
 return escape;
 }  }
   
   
Line 1054  escape sequence. Line 1472  escape sequence.
 Argument:  Argument:
   ptrptr         points to the pattern position pointer    ptrptr         points to the pattern position pointer
   negptr         points to a boolean that is set TRUE for negation else FALSE    negptr         points to a boolean that is set TRUE for negation else FALSE
  dptr           points to an int that is set to the detailed property value  ptypeptr       points to an unsigned int that is set to the type value
   pdataptr       points to an unsigned int that is set to the detailed property value
   errorcodeptr   points to the error code variable    errorcodeptr   points to the error code variable
   
Returns:         type value from ucp_type_table, or -1 for an invalid typeReturns:         TRUE if the type value was found, or FALSE for an invalid type
 */  */
   
static intstatic BOOL
get_ucp(const uschar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr)get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, unsigned int *ptypeptr,
   unsigned int *pdataptr, int *errorcodeptr)
 {  {
int c, i, bot, top;pcre_uchar c;
const uschar *ptr = *ptrptr;int i, bot, top;
char name[32];const pcre_uchar *ptr = *ptrptr;
 pcre_uchar name[32];
   
 c = *(++ptr);  c = *(++ptr);
if (c == 0) goto ERROR_RETURN;if (c == CHAR_NULL) goto ERROR_RETURN;
   
 *negptr = FALSE;  *negptr = FALSE;
   
Line 1082  if (c == CHAR_LEFT_CURLY_BRACKET) Line 1503  if (c == CHAR_LEFT_CURLY_BRACKET)
     *negptr = TRUE;      *negptr = TRUE;
     ptr++;      ptr++;
     }      }
  for (i = 0; i < (int)sizeof(name) - 1; i++)  for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++)
     {      {
     c = *(++ptr);      c = *(++ptr);
    if (c == 0) goto ERROR_RETURN;    if (c == CHAR_NULL) goto ERROR_RETURN;
     if (c == CHAR_RIGHT_CURLY_BRACKET) break;      if (c == CHAR_RIGHT_CURLY_BRACKET) break;
     name[i] = c;      name[i] = c;
     }      }
Line 1106  else Line 1527  else
 /* Search for a recognized property name using binary chop */  /* Search for a recognized property name using binary chop */
   
 bot = 0;  bot = 0;
top = _pcre_utt_size;top = PRIV(utt_size);
   
 while (bot < top)  while (bot < top)
   {    {
     int r;
   i = (bot + top) >> 1;    i = (bot + top) >> 1;
  c = strcmp(name, _pcre_utt_names + _pcre_utt[i].name_offset);  r = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
  if (c == 0)  if (r == 0)
     {      {
    *dptr = _pcre_utt[i].value;    *ptypeptr = PRIV(utt)[i].type;
    return _pcre_utt[i].type;    *pdataptr = PRIV(utt)[i].value;
     return TRUE;
     }      }
  if (c > 0) bot = i + 1; else top = i;  if (r > 0) bot = i + 1; else top = i;
   }    }
   
 *errorcodeptr = ERR47;  *errorcodeptr = ERR47;
 *ptrptr = ptr;  *ptrptr = ptr;
return -1;return FALSE;
   
 ERROR_RETURN:  ERROR_RETURN:
 *errorcodeptr = ERR46;  *errorcodeptr = ERR46;
 *ptrptr = ptr;  *ptrptr = ptr;
return -1;return FALSE;
 }  }
 #endif  #endif
   
   
   
   
 /*************************************************  /*************************************************
 *         Read repeat counts                     *  *         Read repeat counts                     *
 *************************************************/  *************************************************/
Line 1153  Returns:         pointer to '}' on success; Line 1575  Returns:         pointer to '}' on success;
                  current ptr on error, with errorcodeptr set non-zero                   current ptr on error, with errorcodeptr set non-zero
 */  */
   
static const uschar *static const pcre_uchar *
read_repeat_counts(const uschar *p, int *minp, int *maxp, int *errorcodeptr)read_repeat_counts(const pcre_uchar *p, int *minp, int *maxp, int *errorcodeptr)
 {  {
 int min = 0;  int min = 0;
 int max = -1;  int max = -1;
Line 1162  int max = -1; Line 1584  int max = -1;
 /* Read the minimum value and do a paranoid check: a negative value indicates  /* Read the minimum value and do a paranoid check: a negative value indicates
 an integer overflow. */  an integer overflow. */
   
while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - CHAR_0;while (IS_DIGIT(*p)) min = min * 10 + (int)(*p++ - CHAR_0);
 if (min < 0 || min > 65535)  if (min < 0 || min > 65535)
   {    {
   *errorcodeptr = ERR5;    *errorcodeptr = ERR5;
Line 1177  if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else Line 1599  if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else
   if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)    if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
     {      {
     max = 0;      max = 0;
    while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - CHAR_0;    while(IS_DIGIT(*p)) max = max * 10 + (int)(*p++ - CHAR_0);
     if (max < 0 || max > 65535)      if (max < 0 || max > 65535)
       {        {
       *errorcodeptr = ERR5;        *errorcodeptr = ERR5;
Line 1202  return p; Line 1624  return p;
   
   
 /*************************************************  /*************************************************
 *  Subroutine for finding forward reference      *  
 *************************************************/  
   
 /* This recursive function is called only from find_parens() below. The  
 top-level call starts at the beginning of the pattern. All other calls must  
 start at a parenthesis. It scans along a pattern's text looking for capturing  
 subpatterns, and counting them. If it finds a named pattern that matches the  
 name it is given, it returns its number. Alternatively, if the name is NULL, it  
 returns when it reaches a given numbered subpattern. Recursion is used to keep  
 track of subpatterns that reset the capturing group numbers - the (?| feature.  
   
 This function was originally called only from the second pass, in which we know  
 that if (?< or (?' or (?P< is encountered, the name will be correctly  
 terminated because that is checked in the first pass. There is now one call to  
 this function in the first pass, to check for a recursive back reference by  
 name (so that we can make the whole group atomic). In this case, we need check  
 only up to the current position in the pattern, and that is still OK because  
 and previous occurrences will have been checked. To make this work, the test  
 for "end of pattern" is a check against cd->end_pattern in the main loop,  
 instead of looking for a binary zero. This means that the special first-pass  
 call can adjust cd->end_pattern temporarily. (Checks for binary zero while  
 processing items within the loop are OK, because afterwards the main loop will  
 terminate.)  
   
 Arguments:  
   ptrptr       address of the current character pointer (updated)  
   cd           compile background data  
   name         name to seek, or NULL if seeking a numbered subpattern  
   lorn         name length, or subpattern number if name is NULL  
   xmode        TRUE if we are in /x mode  
   utf8         TRUE if we are in UTF-8 mode  
   count        pointer to the current capturing subpattern number (updated)  
   
 Returns:       the number of the named subpattern, or -1 if not found  
 */  
   
 static int  
 find_parens_sub(uschar **ptrptr, compile_data *cd, const uschar *name, int lorn,  
   BOOL xmode, BOOL utf8, int *count)  
 {  
 uschar *ptr = *ptrptr;  
 int start_count = *count;  
 int hwm_count = start_count;  
 BOOL dup_parens = FALSE;  
   
 /* If the first character is a parenthesis, check on the type of group we are  
 dealing with. The very first call may not start with a parenthesis. */  
   
 if (ptr[0] == CHAR_LEFT_PARENTHESIS)  
   {  
   /* Handle specials such as (*SKIP) or (*UTF8) etc. */  
   
   if (ptr[1] == CHAR_ASTERISK) ptr += 2;  
   
   /* Handle a normal, unnamed capturing parenthesis. */  
   
   else if (ptr[1] != CHAR_QUESTION_MARK)  
     {  
     *count += 1;  
     if (name == NULL && *count == lorn) return *count;  
     ptr++;  
     }  
   
   /* All cases now have (? at the start. Remember when we are in a group  
   where the parenthesis numbers are duplicated. */  
   
   else if (ptr[2] == CHAR_VERTICAL_LINE)  
     {  
     ptr += 3;  
     dup_parens = TRUE;  
     }  
   
   /* Handle comments; all characters are allowed until a ket is reached. */  
   
   else if (ptr[2] == CHAR_NUMBER_SIGN)  
     {  
     for (ptr += 3; *ptr != 0; ptr++) if (*ptr == CHAR_RIGHT_PARENTHESIS) break;  
     goto FAIL_EXIT;  
     }  
   
   /* Handle a condition. If it is an assertion, just carry on so that it  
   is processed as normal. If not, skip to the closing parenthesis of the  
   condition (there can't be any nested parens). */  
   
   else if (ptr[2] == CHAR_LEFT_PARENTHESIS)  
     {  
     ptr += 2;  
     if (ptr[1] != CHAR_QUESTION_MARK)  
       {  
       while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;  
       if (*ptr != 0) ptr++;  
       }  
     }  
   
   /* Start with (? but not a condition. */  
   
   else  
     {  
     ptr += 2;  
     if (*ptr == CHAR_P) ptr++;                      /* Allow optional P */  
   
     /* We have to disambiguate (?<! and (?<= from (?<name> for named groups */  
   
     if ((*ptr == CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK &&  
         ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE)  
       {  
       int term;  
       const uschar *thisname;  
       *count += 1;  
       if (name == NULL && *count == lorn) return *count;  
       term = *ptr++;  
       if (term == CHAR_LESS_THAN_SIGN) term = CHAR_GREATER_THAN_SIGN;  
       thisname = ptr;  
       while (*ptr != term) ptr++;  
       if (name != NULL && lorn == ptr - thisname &&  
           strncmp((const char *)name, (const char *)thisname, lorn) == 0)  
         return *count;  
       term++;  
       }  
     }  
   }  
   
 /* Past any initial parenthesis handling, scan for parentheses or vertical  
 bars. Stop if we get to cd->end_pattern. Note that this is important for the  
 first-pass call when this value is temporarily adjusted to stop at the current  
 position. So DO NOT change this to a test for binary zero. */  
   
 for (; ptr < cd->end_pattern; ptr++)  
   {  
   /* Skip over backslashed characters and also entire \Q...\E */  
   
   if (*ptr == CHAR_BACKSLASH)  
     {  
     if (*(++ptr) == 0) goto FAIL_EXIT;  
     if (*ptr == CHAR_Q) for (;;)  
       {  
       while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {};  
       if (*ptr == 0) goto FAIL_EXIT;  
       if (*(++ptr) == CHAR_E) break;  
       }  
     continue;  
     }  
   
   /* Skip over character classes; this logic must be similar to the way they  
   are handled for real. If the first character is '^', skip it. Also, if the  
   first few characters (either before or after ^) are \Q\E or \E we skip them  
   too. This makes for compatibility with Perl. Note the use of STR macros to  
   encode "Q\\E" so that it works in UTF-8 on EBCDIC platforms. */  
   
   if (*ptr == CHAR_LEFT_SQUARE_BRACKET)  
     {  
     BOOL negate_class = FALSE;  
     for (;;)  
       {  
       if (ptr[1] == CHAR_BACKSLASH)  
         {  
         if (ptr[2] == CHAR_E)  
           ptr+= 2;  
         else if (strncmp((const char *)ptr+2,  
                  STR_Q STR_BACKSLASH STR_E, 3) == 0)  
           ptr += 4;  
         else  
           break;  
         }  
       else if (!negate_class && ptr[1] == CHAR_CIRCUMFLEX_ACCENT)  
         {  
         negate_class = TRUE;  
         ptr++;  
         }  
       else break;  
       }  
   
     /* If the next character is ']', it is a data character that must be  
     skipped, except in JavaScript compatibility mode. */  
   
     if (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET &&  
         (cd->external_options & PCRE_JAVASCRIPT_COMPAT) == 0)  
       ptr++;  
   
     while (*(++ptr) != CHAR_RIGHT_SQUARE_BRACKET)  
       {  
       if (*ptr == 0) return -1;  
       if (*ptr == CHAR_BACKSLASH)  
         {  
         if (*(++ptr) == 0) goto FAIL_EXIT;  
         if (*ptr == CHAR_Q) for (;;)  
           {  
           while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {};  
           if (*ptr == 0) goto FAIL_EXIT;  
           if (*(++ptr) == CHAR_E) break;  
           }  
         continue;  
         }  
       }  
     continue;  
     }  
   
   /* Skip comments in /x mode */  
   
   if (xmode && *ptr == CHAR_NUMBER_SIGN)  
     {  
     ptr++;  
     while (*ptr != 0)  
       {  
       if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }  
       ptr++;  
 #ifdef SUPPORT_UTF8  
       if (utf8) while ((*ptr & 0xc0) == 0x80) ptr++;  
 #endif  
       }  
     if (*ptr == 0) goto FAIL_EXIT;  
     continue;  
     }  
   
   /* Check for the special metacharacters */  
   
   if (*ptr == CHAR_LEFT_PARENTHESIS)  
     {  
     int rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf8, count);  
     if (rc > 0) return rc;  
     if (*ptr == 0) goto FAIL_EXIT;  
     }  
   
   else if (*ptr == CHAR_RIGHT_PARENTHESIS)  
     {  
     if (dup_parens && *count < hwm_count) *count = hwm_count;  
     goto FAIL_EXIT;  
     }  
   
   else if (*ptr == CHAR_VERTICAL_LINE && dup_parens)  
     {  
     if (*count > hwm_count) hwm_count = *count;  
     *count = start_count;  
     }  
   }  
   
 FAIL_EXIT:  
 *ptrptr = ptr;  
 return -1;  
 }  
   
   
   
   
 /*************************************************  
 *       Find forward referenced subpattern       *  
 *************************************************/  
   
 /* This function scans along a pattern's text looking for capturing  
 subpatterns, and counting them. If it finds a named pattern that matches the  
 name it is given, it returns its number. Alternatively, if the name is NULL, it  
 returns when it reaches a given numbered subpattern. This is used for forward  
 references to subpatterns. We used to be able to start this scan from the  
 current compiling point, using the current count value from cd->bracount, and  
 do it all in a single loop, but the addition of the possibility of duplicate  
 subpattern numbers means that we have to scan from the very start, in order to  
 take account of such duplicates, and to use a recursive function to keep track  
 of the different types of group.  
   
 Arguments:  
   cd           compile background data  
   name         name to seek, or NULL if seeking a numbered subpattern  
   lorn         name length, or subpattern number if name is NULL  
   xmode        TRUE if we are in /x mode  
   utf8         TRUE if we are in UTF-8 mode  
   
 Returns:       the number of the found subpattern, or -1 if not found  
 */  
   
 static int  
 find_parens(compile_data *cd, const uschar *name, int lorn, BOOL xmode,  
   BOOL utf8)  
 {  
 uschar *ptr = (uschar *)cd->start_pattern;  
 int count = 0;  
 int rc;  
   
 /* If the pattern does not start with an opening parenthesis, the first call  
 to find_parens_sub() will scan right to the end (if necessary). However, if it  
 does start with a parenthesis, find_parens_sub() will return when it hits the  
 matching closing parens. That is why we have to have a loop. */  
   
 for (;;)  
   {  
   rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf8, &count);  
   if (rc > 0 || *ptr++ == 0) break;  
   }  
   
 return rc;  
 }  
   
   
   
   
 /*************************************************  
 *      Find first significant op code            *  *      Find first significant op code            *
 *************************************************/  *************************************************/
   
Line 1513  Arguments: Line 1640  Arguments:
 Returns:       pointer to the first significant opcode  Returns:       pointer to the first significant opcode
 */  */
   
static const uschar*static const pcre_uchar*
first_significant_code(const uschar *code, BOOL skipassert)first_significant_code(const pcre_uchar *code, BOOL skipassert)
 {  {
 for (;;)  for (;;)
   {    {
Line 1525  for (;;) Line 1652  for (;;)
     case OP_ASSERTBACK_NOT:      case OP_ASSERTBACK_NOT:
     if (!skipassert) return code;      if (!skipassert) return code;
     do code += GET(code, 1); while (*code == OP_ALT);      do code += GET(code, 1); while (*code == OP_ALT);
    code += _pcre_OP_lengths[*code];    code += PRIV(OP_lengths)[*code];
     break;      break;
   
     case OP_WORD_BOUNDARY:      case OP_WORD_BOUNDARY:
Line 1535  for (;;) Line 1662  for (;;)
   
     case OP_CALLOUT:      case OP_CALLOUT:
     case OP_CREF:      case OP_CREF:
    case OP_NCREF:    case OP_DNCREF:
     case OP_RREF:      case OP_RREF:
    case OP_NRREF:    case OP_DNRREF:
     case OP_DEF:      case OP_DEF:
    code += _pcre_OP_lengths[*code];    code += PRIV(OP_lengths)[*code];
     break;      break;
   
     default:      default:
Line 1551  for (;;) Line 1678  for (;;)
   
   
   
   
 /*************************************************  /*************************************************
 *        Find the fixed length of a branch       *  *        Find the fixed length of a branch       *
 *************************************************/  *************************************************/
Line 1569  and doing the check at the end; a flag specifies which Line 1695  and doing the check at the end; a flag specifies which
   
 Arguments:  Arguments:
   code     points to the start of the pattern (the bracket)    code     points to the start of the pattern (the bracket)
  utf8     TRUE in UTF-8 mode  utf      TRUE in UTF-8 / UTF-16 / UTF-32 mode
   atend    TRUE if called when the pattern is complete    atend    TRUE if called when the pattern is complete
   cd       the "compile data" structure    cd       the "compile data" structure
   
Line 1581  Returns:   the fixed length, Line 1707  Returns:   the fixed length,
 */  */
   
 static int  static int
find_fixedlength(uschar *code, BOOL utf8, BOOL atend, compile_data *cd)find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd)
 {  {
 int length = -1;  int length = -1;
   
 register int branchlength = 0;  register int branchlength = 0;
register uschar *cc = code + 1 + LINK_SIZE;register pcre_uchar *cc = code + 1 + LINK_SIZE;
   
 /* Scan along the opcodes for this branch. If we get to the end of the  /* 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. */  branch, check the length against that of the other branches. */
Line 1594  branch, check the length against that of the other bra Line 1720  branch, check the length against that of the other bra
 for (;;)  for (;;)
   {    {
   int d;    int d;
  uschar *ce, *cs;  pcre_uchar *ce, *cs;
  register int op = *cc;  register pcre_uchar op = *cc;
 
   switch (op)    switch (op)
     {      {
     /* We only need to continue for OP_CBRA (normal capturing bracket) and      /* We only need to continue for OP_CBRA (normal capturing bracket) and
Line 1608  for (;;) Line 1735  for (;;)
     case OP_ONCE:      case OP_ONCE:
     case OP_ONCE_NC:      case OP_ONCE_NC:
     case OP_COND:      case OP_COND:
    d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), utf8, atend, cd);    d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd);
     if (d < 0) return d;      if (d < 0) return d;
     branchlength += d;      branchlength += d;
     do cc += GET(cc, 1); while (*cc == OP_ALT);      do cc += GET(cc, 1); while (*cc == OP_ALT);
Line 1639  for (;;) Line 1766  for (;;)
   
     case OP_RECURSE:      case OP_RECURSE:
     if (!atend) return -3;      if (!atend) return -3;
    cs = ce = (uschar *)cd->start_code + GET(cc, 1);  /* Start subpattern */    cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1);  /* Start subpattern */
    do ce += GET(ce, 1); while (*ce == OP_ALT);       /* End subpattern */    do ce += GET(ce, 1); while (*ce == OP_ALT);           /* End subpattern */
    if (cc > cs && cc < ce) return -1;                /* Recursion */    if (cc > cs && cc < ce) return -1;                    /* Recursion */
    d = find_fixedlength(cs + 2, utf8, atend, cd);    d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd);
     if (d < 0) return d;      if (d < 0) return d;
     branchlength += d;      branchlength += d;
     cc += 1 + LINK_SIZE;      cc += 1 + LINK_SIZE;
Line 1655  for (;;) Line 1782  for (;;)
     case OP_ASSERTBACK:      case OP_ASSERTBACK:
     case OP_ASSERTBACK_NOT:      case OP_ASSERTBACK_NOT:
     do cc += GET(cc, 1); while (*cc == OP_ALT);      do cc += GET(cc, 1); while (*cc == OP_ALT);
    /* Fall through */    cc += PRIV(OP_lengths)[*cc];
     break;
   
     /* Skip over things that don't match chars */      /* Skip over things that don't match chars */
   
Line 1663  for (;;) Line 1791  for (;;)
     case OP_PRUNE_ARG:      case OP_PRUNE_ARG:
     case OP_SKIP_ARG:      case OP_SKIP_ARG:
     case OP_THEN_ARG:      case OP_THEN_ARG:
    cc += cc[1] + _pcre_OP_lengths[*cc];    cc += cc[1] + PRIV(OP_lengths)[*cc];
     break;      break;
   
     case OP_CALLOUT:      case OP_CALLOUT:
Line 1673  for (;;) Line 1801  for (;;)
     case OP_COMMIT:      case OP_COMMIT:
     case OP_CREF:      case OP_CREF:
     case OP_DEF:      case OP_DEF:
       case OP_DNCREF:
       case OP_DNRREF:
     case OP_DOLL:      case OP_DOLL:
     case OP_DOLLM:      case OP_DOLLM:
     case OP_EOD:      case OP_EOD:
     case OP_EODN:      case OP_EODN:
     case OP_FAIL:      case OP_FAIL:
     case OP_NCREF:  
     case OP_NRREF:  
     case OP_NOT_WORD_BOUNDARY:      case OP_NOT_WORD_BOUNDARY:
     case OP_PRUNE:      case OP_PRUNE:
     case OP_REVERSE:      case OP_REVERSE:
Line 1690  for (;;) Line 1818  for (;;)
     case OP_SOM:      case OP_SOM:
     case OP_THEN:      case OP_THEN:
     case OP_WORD_BOUNDARY:      case OP_WORD_BOUNDARY:
    cc += _pcre_OP_lengths[*cc];    cc += PRIV(OP_lengths)[*cc];
     break;      break;
   
     /* Handle literal characters */      /* Handle literal characters */
Line 1701  for (;;) Line 1829  for (;;)
     case OP_NOTI:      case OP_NOTI:
     branchlength++;      branchlength++;
     cc += 2;      cc += 2;
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
    if (utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
 #endif  #endif
     break;      break;
   
Line 1713  for (;;) Line 1841  for (;;)
     case OP_EXACTI:      case OP_EXACTI:
     case OP_NOTEXACT:      case OP_NOTEXACT:
     case OP_NOTEXACTI:      case OP_NOTEXACTI:
    branchlength += GET2(cc,1);    branchlength += (int)GET2(cc,1);
    cc += 4;    cc += 2 + IMM2_SIZE;
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
    if (utf8 && cc[-1] >= 0xc0) cc += _pcre_utf8_table4[cc[-1] & 0x3f];    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
 #endif  #endif
     break;      break;
   
     case OP_TYPEEXACT:      case OP_TYPEEXACT:
     branchlength += GET2(cc,1);      branchlength += GET2(cc,1);
    if (cc[3] == OP_PROP || cc[3] == OP_NOTPROP) cc += 2;    if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP)
    cc += 4;      cc += 2;
     cc += 1 + IMM2_SIZE + 1;
     break;      break;
   
     /* Handle single-char matchers */      /* Handle single-char matchers */
Line 1757  for (;;) Line 1886  for (;;)
   
     /* Check a class for variable quantification */      /* Check a class for variable quantification */
   
#ifdef SUPPORT_UTF8    case OP_CLASS:
     case OP_NCLASS:
 #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
     case OP_XCLASS:      case OP_XCLASS:
    cc += GET(cc, 1) - 33;    /* The original code caused an unsigned overflow in 64 bit systems,
    /* Fall through */    so now we use a conditional statement. */
     if (op == OP_XCLASS)
       cc += GET(cc, 1);
     else
       cc += PRIV(OP_lengths)[OP_CLASS];
 #else
     cc += PRIV(OP_lengths)[OP_CLASS];
 #endif  #endif
   
     case OP_CLASS:  
     case OP_NCLASS:  
     cc += 33;  
   
     switch (*cc)      switch (*cc)
       {        {
       case OP_CRPLUS:  
       case OP_CRMINPLUS:  
       case OP_CRSTAR:        case OP_CRSTAR:
       case OP_CRMINSTAR:        case OP_CRMINSTAR:
         case OP_CRPLUS:
         case OP_CRMINPLUS:
       case OP_CRQUERY:        case OP_CRQUERY:
       case OP_CRMINQUERY:        case OP_CRMINQUERY:
         case OP_CRPOSSTAR:
         case OP_CRPOSPLUS:
         case OP_CRPOSQUERY:
       return -1;        return -1;
   
       case OP_CRRANGE:        case OP_CRRANGE:
       case OP_CRMINRANGE:        case OP_CRMINRANGE:
      if (GET2(cc,1) != GET2(cc,3)) return -1;      case OP_CRPOSRANGE:
      branchlength += GET2(cc,1);      if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1;
      cc += 5;      branchlength += (int)GET2(cc,1);
       cc += 1 + 2 * IMM2_SIZE;
       break;        break;
   
       default:        default:
Line 1847  for (;;) Line 1984  for (;;)
     case OP_QUERYI:      case OP_QUERYI:
     case OP_REF:      case OP_REF:
     case OP_REFI:      case OP_REFI:
       case OP_DNREF:
       case OP_DNREFI:
     case OP_SBRA:      case OP_SBRA:
     case OP_SBRAPOS:      case OP_SBRAPOS:
     case OP_SCBRA:      case OP_SCBRA:
Line 1883  for (;;) Line 2022  for (;;)
   
   
   
   
 /*************************************************  /*************************************************
 *    Scan compiled regex for specific bracket    *  *    Scan compiled regex for specific bracket    *
 *************************************************/  *************************************************/
Line 1896  length. Line 2034  length.
   
 Arguments:  Arguments:
   code        points to start of expression    code        points to start of expression
  utf8        TRUE in UTF-8 mode  utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
   number      the required bracket number or negative to find a lookbehind    number      the required bracket number or negative to find a lookbehind
   
 Returns:      pointer to the opcode for the bracket, or NULL if not found  Returns:      pointer to the opcode for the bracket, or NULL if not found
 */  */
   
const uschar *const pcre_uchar *
_pcre_find_bracket(const uschar *code, BOOL utf8, int number)PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, int number)
 {  {
 for (;;)  for (;;)
   {    {
  register int c = *code;  register pcre_uchar c = *code;
   
   if (c == OP_END) return NULL;    if (c == OP_END) return NULL;
   
Line 1921  for (;;) Line 2059  for (;;)
   
   else if (c == OP_REVERSE)    else if (c == OP_REVERSE)
     {      {
    if (number < 0) return (uschar *)code;    if (number < 0) return (pcre_uchar *)code;
    code += _pcre_OP_lengths[c];    code += PRIV(OP_lengths)[c];
     }      }
   
   /* Handle capturing bracket */    /* Handle capturing bracket */
Line 1930  for (;;) Line 2068  for (;;)
   else if (c == OP_CBRA || c == OP_SCBRA ||    else if (c == OP_CBRA || c == OP_SCBRA ||
            c == OP_CBRAPOS || c == OP_SCBRAPOS)             c == OP_CBRAPOS || c == OP_SCBRAPOS)
     {      {
    int n = GET2(code, 1+LINK_SIZE);    int n = (int)GET2(code, 1+LINK_SIZE);
    if (n == number) return (uschar *)code;    if (n == number) return (pcre_uchar *)code;
    code += _pcre_OP_lengths[c];    code += PRIV(OP_lengths)[c];
     }      }
   
   /* Otherwise, we can get the item's length from the table, except that for    /* Otherwise, we can get the item's length from the table, except that for
Line 1960  for (;;) Line 2098  for (;;)
       case OP_TYPEMINUPTO:        case OP_TYPEMINUPTO:
       case OP_TYPEEXACT:        case OP_TYPEEXACT:
       case OP_TYPEPOSUPTO:        case OP_TYPEPOSUPTO:
      if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2;      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
         code += 2;
       break;        break;
   
       case OP_MARK:        case OP_MARK:
       case OP_PRUNE_ARG:        case OP_PRUNE_ARG:
       case OP_SKIP_ARG:        case OP_SKIP_ARG:
       code += code[1];  
       break;  
   
       case OP_THEN_ARG:        case OP_THEN_ARG:
       code += code[1];        code += code[1];
       break;        break;
Line 1976  for (;;) Line 2112  for (;;)
   
     /* Add in the fixed length from the table */      /* Add in the fixed length from the table */
   
    code += _pcre_OP_lengths[c];    code += PRIV(OP_lengths)[c];
   
   /* In UTF-8 mode, opcodes that are followed by a character may be followed by    /* In UTF-8 mode, opcodes that are followed by a character may be followed by
   a multi-byte character. The length in the table is a minimum, so we have to    a multi-byte character. The length in the table is a minimum, so we have to
   arrange to skip the extra bytes. */    arrange to skip the extra bytes. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
    if (utf8) switch(c)    if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
       case OP_CHARI:        case OP_CHARI:
Line 2013  for (;;) Line 2149  for (;;)
       case OP_MINQUERYI:        case OP_MINQUERYI:
       case OP_POSQUERY:        case OP_POSQUERY:
       case OP_POSQUERYI:        case OP_POSQUERYI:
      if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f];      if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
       break;        break;
       }        }
 #else  #else
    (void)(utf8);  /* Keep compiler happy by referencing function argument */    (void)(utf);  /* Keep compiler happy by referencing function argument */
 #endif  #endif
     }      }
   }    }
Line 2034  instance of OP_RECURSE. Line 2170  instance of OP_RECURSE.
   
 Arguments:  Arguments:
   code        points to start of expression    code        points to start of expression
  utf8        TRUE in UTF-8 mode  utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
   
 Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found  Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
 */  */
   
static const uschar *static const pcre_uchar *
find_recurse(const uschar *code, BOOL utf8)find_recurse(const pcre_uchar *code, BOOL utf)
 {  {
 for (;;)  for (;;)
   {    {
  register int c = *code;  register pcre_uchar c = *code;
   if (c == OP_END) return NULL;    if (c == OP_END) return NULL;
   if (c == OP_RECURSE) return code;    if (c == OP_RECURSE) return code;
   
Line 2079  for (;;) Line 2215  for (;;)
       case OP_TYPEUPTO:        case OP_TYPEUPTO:
       case OP_TYPEMINUPTO:        case OP_TYPEMINUPTO:
       case OP_TYPEEXACT:        case OP_TYPEEXACT:
      if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2;      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
         code += 2;
       break;        break;
   
       case OP_MARK:        case OP_MARK:
       case OP_PRUNE_ARG:        case OP_PRUNE_ARG:
       case OP_SKIP_ARG:        case OP_SKIP_ARG:
       code += code[1];  
       break;  
   
       case OP_THEN_ARG:        case OP_THEN_ARG:
       code += code[1];        code += code[1];
       break;        break;
Line 2095  for (;;) Line 2229  for (;;)
   
     /* Add in the fixed length from the table */      /* Add in the fixed length from the table */
   
    code += _pcre_OP_lengths[c];    code += PRIV(OP_lengths)[c];
   
     /* In UTF-8 mode, opcodes that are followed by a character may be followed      /* In UTF-8 mode, opcodes that are followed by a character may be followed
     by a multi-byte character. The length in the table is a minimum, so we have      by a multi-byte character. The length in the table is a minimum, so we have
     to arrange to skip the extra bytes. */      to arrange to skip the extra bytes. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
    if (utf8) switch(c)    if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
       case OP_CHARI:        case OP_CHARI:
         case OP_NOT:
         case OP_NOTI:
       case OP_EXACT:        case OP_EXACT:
       case OP_EXACTI:        case OP_EXACTI:
         case OP_NOTEXACT:
         case OP_NOTEXACTI:
       case OP_UPTO:        case OP_UPTO:
       case OP_UPTOI:        case OP_UPTOI:
         case OP_NOTUPTO:
         case OP_NOTUPTOI:
       case OP_MINUPTO:        case OP_MINUPTO:
       case OP_MINUPTOI:        case OP_MINUPTOI:
         case OP_NOTMINUPTO:
         case OP_NOTMINUPTOI:
       case OP_POSUPTO:        case OP_POSUPTO:
       case OP_POSUPTOI:        case OP_POSUPTOI:
         case OP_NOTPOSUPTO:
         case OP_NOTPOSUPTOI:
       case OP_STAR:        case OP_STAR:
       case OP_STARI:        case OP_STARI:
         case OP_NOTSTAR:
         case OP_NOTSTARI:
       case OP_MINSTAR:        case OP_MINSTAR:
       case OP_MINSTARI:        case OP_MINSTARI:
         case OP_NOTMINSTAR:
         case OP_NOTMINSTARI:
       case OP_POSSTAR:        case OP_POSSTAR:
       case OP_POSSTARI:        case OP_POSSTARI:
         case OP_NOTPOSSTAR:
         case OP_NOTPOSSTARI:
       case OP_PLUS:        case OP_PLUS:
       case OP_PLUSI:        case OP_PLUSI:
         case OP_NOTPLUS:
         case OP_NOTPLUSI:
       case OP_MINPLUS:        case OP_MINPLUS:
       case OP_MINPLUSI:        case OP_MINPLUSI:
         case OP_NOTMINPLUS:
         case OP_NOTMINPLUSI:
       case OP_POSPLUS:        case OP_POSPLUS:
       case OP_POSPLUSI:        case OP_POSPLUSI:
         case OP_NOTPOSPLUS:
         case OP_NOTPOSPLUSI:
       case OP_QUERY:        case OP_QUERY:
       case OP_QUERYI:        case OP_QUERYI:
         case OP_NOTQUERY:
         case OP_NOTQUERYI:
       case OP_MINQUERY:        case OP_MINQUERY:
       case OP_MINQUERYI:        case OP_MINQUERYI:
         case OP_NOTMINQUERY:
         case OP_NOTMINQUERYI:
       case OP_POSQUERY:        case OP_POSQUERY:
       case OP_POSQUERYI:        case OP_POSQUERYI:
      if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f];      case OP_NOTPOSQUERY:
       case OP_NOTPOSQUERYI:
       if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
       break;        break;
       }        }
 #else  #else
    (void)(utf8);  /* Keep compiler happy by referencing function argument */    (void)(utf);  /* Keep compiler happy by referencing function argument */
 #endif  #endif
     }      }
   }    }
Line 2159  bracket whose current branch will already have been sc Line 2321  bracket whose current branch will already have been sc
 Arguments:  Arguments:
   code        points to start of search    code        points to start of search
   endcode     points to where to stop    endcode     points to where to stop
  utf8        TRUE if in UTF8 mode  utf         TRUE if in UTF-  utf         TRUE if in UTF-8 / UTF-16 / UTF-32 mode
   cd          contains pointers to tables etc.    cd          contains pointers to tables etc.
     recurses    chain of recurse_check to catch mutual recursion
   
 Returns:      TRUE if what is matched could be empty  Returns:      TRUE if what is matched could be empty
 */  */
   
   typedef struct recurse_check {
     struct recurse_check *prev;
     const pcre_uchar *group;
   } recurse_check;
   
 static BOOL  static BOOL
could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8,could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,
  compile_data *cd)  BOOL utf, compile_data *cd, recurse_check *recurses)
 {  {
register int c;register pcre_uchar c;
for (code = first_significant_code(code + _pcre_OP_lengths[*code], TRUE);recurse_check this_recurse;
 
 for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
      code < endcode;       code < endcode;
     code = first_significant_code(code + _pcre_OP_lengths[c], TRUE))     code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))
   {    {
  const uschar *ccode;  const pcre_uchar *ccode;
   
   c = *code;    c = *code;
   
Line 2197  for (code = first_significant_code(code + _pcre_OP_len Line 2367  for (code = first_significant_code(code + _pcre_OP_len
   
   if (c == OP_RECURSE)    if (c == OP_RECURSE)
     {      {
    const uschar *scode;    const pcre_uchar *scode = cd->start_code + GET(code, 1);
     BOOL empty_branch;      BOOL empty_branch;
   
    /* Test for forward reference */    /* Test for forward reference or uncompleted reference. This is disabled
     when called to scan a completed pattern by setting cd->start_workspace to
     NULL. */
   
    for (scode = cd->start_workspace; scode < cd->hwm; scode += LINK_SIZE)    if (cd->start_workspace != NULL)
      if (GET(scode, 0) == code + 1 - cd->start_code) return TRUE;      {
       const pcre_uchar *tcode;
       for (tcode = cd->start_workspace; tcode < cd->hwm; tcode += LINK_SIZE)
         if ((int)GET(tcode, 0) == (int)(code + 1 - cd->start_code)) return TRUE;
       if (GET(scode, 1) == 0) return TRUE;    /* Unclosed */
       }
   
    /* Not a forward reference, test for completed backward reference */    /* If we are scanning a completed pattern, there are no forward references
     and all groups are complete. We need to detect whether this is a recursive
     call, as otherwise there will be an infinite loop. If it is a recursion,
     just skip over it. Simple recursions are easily detected. For mutual
     recursions we keep a chain on the stack. */
   
    empty_branch = FALSE;    else
    scode = cd->start_code + GET(code, 1);      {
    if (GET(scode, 1) == 0) return TRUE;    /* Unclosed */      recurse_check *r = recurses;
       const pcre_uchar *endgroup = scode;
   
    /* Completed backwards reference */      do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
       if (code >= scode && code <= endgroup) continue;  /* Simple recursion */
   
         for (r = recurses; r != NULL; r = r->prev)
           if (r->group == scode) break;
         if (r != NULL) continue;   /* Mutual recursion */
         }
   
       /* Completed reference; scan the referenced group, remembering it on the
       stack chain to detect mutual recursions. */
   
       empty_branch = FALSE;
       this_recurse.prev = recurses;
       this_recurse.group = scode;
   
     do      do
       {        {
      if (could_be_empty_branch(scode, endcode, utf8, cd))      if (could_be_empty_branch(scode, endcode, utf, cd, &this_recurse))
         {          {
         empty_branch = TRUE;          empty_branch = TRUE;
         break;          break;
Line 2233  for (code = first_significant_code(code + _pcre_OP_len Line 2428  for (code = first_significant_code(code + _pcre_OP_len
   if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO ||    if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO ||
       c == OP_BRAPOSZERO)        c == OP_BRAPOSZERO)
     {      {
    code += _pcre_OP_lengths[c];    code += PRIV(OP_lengths)[c];
     do code += GET(code, 1); while (*code == OP_ALT);      do code += GET(code, 1); while (*code == OP_ALT);
     c = *code;      c = *code;
     continue;      continue;
Line 2271  for (code = first_significant_code(code + _pcre_OP_len Line 2466  for (code = first_significant_code(code + _pcre_OP_len
       empty_branch = FALSE;        empty_branch = FALSE;
       do        do
         {          {
        if (!empty_branch && could_be_empty_branch(code, endcode, utf8, cd))        if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, NULL))
           empty_branch = TRUE;            empty_branch = TRUE;
         code += GET(code, 1);          code += GET(code, 1);
         }          }
Line 2289  for (code = first_significant_code(code + _pcre_OP_len Line 2484  for (code = first_significant_code(code + _pcre_OP_len
     {      {
     /* Check for quantifiers after a class. XCLASS is used for classes that      /* Check for quantifiers after a class. XCLASS is used for classes that
     cannot be represented just by a bit map. This includes negated single      cannot be represented just by a bit map. This includes negated single
    high-valued characters. The length in _pcre_OP_lengths[] is zero; the    high-valued characters. The length in PRIV(OP_lengths)[] is zero; the
     actual length is stored in the compiled code, so we must update "code"      actual length is stored in the compiled code, so we must update "code"
     here. */      here. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
     case OP_XCLASS:      case OP_XCLASS:
     ccode = code += GET(code, 1);      ccode = code += GET(code, 1);
     goto CHECK_CLASS_REPEAT;      goto CHECK_CLASS_REPEAT;
Line 2301  for (code = first_significant_code(code + _pcre_OP_len Line 2496  for (code = first_significant_code(code + _pcre_OP_len
   
     case OP_CLASS:      case OP_CLASS:
     case OP_NCLASS:      case OP_NCLASS:
    ccode = code + 33;    ccode = code + PRIV(OP_lengths)[OP_CLASS];
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
     CHECK_CLASS_REPEAT:      CHECK_CLASS_REPEAT:
 #endif  #endif
   
Line 2313  for (code = first_significant_code(code + _pcre_OP_len Line 2508  for (code = first_significant_code(code + _pcre_OP_len
       case OP_CRMINSTAR:        case OP_CRMINSTAR:
       case OP_CRQUERY:        case OP_CRQUERY:
       case OP_CRMINQUERY:        case OP_CRMINQUERY:
         case OP_CRPOSSTAR:
         case OP_CRPOSQUERY:
       break;        break;
   
       default:                   /* Non-repeat => class must match */        default:                   /* Non-repeat => class must match */
       case OP_CRPLUS:            /* These repeats aren't empty */        case OP_CRPLUS:            /* These repeats aren't empty */
       case OP_CRMINPLUS:        case OP_CRMINPLUS:
         case OP_CRPOSPLUS:
       return FALSE;        return FALSE;
   
       case OP_CRRANGE:        case OP_CRRANGE:
       case OP_CRMINRANGE:        case OP_CRMINRANGE:
         case OP_CRPOSRANGE:
       if (GET2(ccode, 1) > 0) return FALSE;  /* Minimum > 0 */        if (GET2(ccode, 1) > 0) return FALSE;  /* Minimum > 0 */
       break;        break;
       }        }
Line 2329  for (code = first_significant_code(code + _pcre_OP_len Line 2528  for (code = first_significant_code(code + _pcre_OP_len
   
     /* Opcodes that must match a character */      /* Opcodes that must match a character */
   
       case OP_ANY:
       case OP_ALLANY:
       case OP_ANYBYTE:
   
     case OP_PROP:      case OP_PROP:
     case OP_NOTPROP:      case OP_NOTPROP:
       case OP_ANYNL:
   
       case OP_NOT_HSPACE:
       case OP_HSPACE:
       case OP_NOT_VSPACE:
       case OP_VSPACE:
     case OP_EXTUNI:      case OP_EXTUNI:
   
     case OP_NOT_DIGIT:      case OP_NOT_DIGIT:
     case OP_DIGIT:      case OP_DIGIT:
     case OP_NOT_WHITESPACE:      case OP_NOT_WHITESPACE:
     case OP_WHITESPACE:      case OP_WHITESPACE:
     case OP_NOT_WORDCHAR:      case OP_NOT_WORDCHAR:
     case OP_WORDCHAR:      case OP_WORDCHAR:
    case OP_ANY:
    case OP_ALLANY: 
    case OP_ANYBYTE: 
     case OP_CHAR:      case OP_CHAR:
     case OP_CHARI:      case OP_CHARI:
     case OP_NOT:      case OP_NOT:
     case OP_NOTI:      case OP_NOTI:
   
     case OP_PLUS:      case OP_PLUS:
       case OP_PLUSI:
     case OP_MINPLUS:      case OP_MINPLUS:
    case OP_POSPLUS:    case OP_MINPLUSI:
    case OP_EXACT:
     case OP_NOTPLUS:      case OP_NOTPLUS:
       case OP_NOTPLUSI:
     case OP_NOTMINPLUS:      case OP_NOTMINPLUS:
       case OP_NOTMINPLUSI:
   
       case OP_POSPLUS:
       case OP_POSPLUSI:
     case OP_NOTPOSPLUS:      case OP_NOTPOSPLUS:
       case OP_NOTPOSPLUSI:
   
       case OP_EXACT:
       case OP_EXACTI:
     case OP_NOTEXACT:      case OP_NOTEXACT:
       case OP_NOTEXACTI:
   
     case OP_TYPEPLUS:      case OP_TYPEPLUS:
     case OP_TYPEMINPLUS:      case OP_TYPEMINPLUS:
     case OP_TYPEPOSPLUS:      case OP_TYPEPOSPLUS:
     case OP_TYPEEXACT:      case OP_TYPEEXACT:
   
     return FALSE;      return FALSE;
   
     /* These are going to continue, as they may be empty, but we have to      /* These are going to continue, as they may be empty, but we have to
Line 2376  for (code = first_significant_code(code + _pcre_OP_len Line 2598  for (code = first_significant_code(code + _pcre_OP_len
     case OP_TYPEUPTO:      case OP_TYPEUPTO:
     case OP_TYPEMINUPTO:      case OP_TYPEMINUPTO:
     case OP_TYPEPOSUPTO:      case OP_TYPEPOSUPTO:
    if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2;    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
       code += 2;
     break;      break;
   
     /* End of branch */      /* End of branch */
Line 2389  for (code = first_significant_code(code + _pcre_OP_len Line 2612  for (code = first_significant_code(code + _pcre_OP_len
     return TRUE;      return TRUE;
   
     /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO,      /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO,
    MINUPTO, and POSUPTO may be followed by a multibyte character */    MINUPTO, and POSUPTO and their caseless and negative versions may be
     followed by a multibyte character. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     case OP_STAR:      case OP_STAR:
     case OP_STARI:      case OP_STARI:
       case OP_NOTSTAR:
       case OP_NOTSTARI:
   
     case OP_MINSTAR:      case OP_MINSTAR:
     case OP_MINSTARI:      case OP_MINSTARI:
       case OP_NOTMINSTAR:
       case OP_NOTMINSTARI:
   
     case OP_POSSTAR:      case OP_POSSTAR:
     case OP_POSSTARI:      case OP_POSSTARI:
       case OP_NOTPOSSTAR:
       case OP_NOTPOSSTARI:
   
     case OP_QUERY:      case OP_QUERY:
     case OP_QUERYI:      case OP_QUERYI:
       case OP_NOTQUERY:
       case OP_NOTQUERYI:
   
     case OP_MINQUERY:      case OP_MINQUERY:
     case OP_MINQUERYI:      case OP_MINQUERYI:
       case OP_NOTMINQUERY:
       case OP_NOTMINQUERYI:
   
     case OP_POSQUERY:      case OP_POSQUERY:
     case OP_POSQUERYI:      case OP_POSQUERYI:
    if (utf8 && code[1] >= 0xc0) code += _pcre_utf8_table4[code[1] & 0x3f];    case OP_NOTPOSQUERY:
     case OP_NOTPOSQUERYI:
 
     if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]);
     break;      break;
   
     case OP_UPTO:      case OP_UPTO:
     case OP_UPTOI:      case OP_UPTOI:
       case OP_NOTUPTO:
       case OP_NOTUPTOI:
   
     case OP_MINUPTO:      case OP_MINUPTO:
     case OP_MINUPTOI:      case OP_MINUPTOI:
       case OP_NOTMINUPTO:
       case OP_NOTMINUPTOI:
   
     case OP_POSUPTO:      case OP_POSUPTO:
     case OP_POSUPTOI:      case OP_POSUPTOI:
    if (utf8 && code[3] >= 0xc0) code += _pcre_utf8_table4[code[3] & 0x3f];    case OP_NOTPOSUPTO:
     case OP_NOTPOSUPTOI:
 
     if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]);
     break;      break;
 #endif  #endif
   
Line 2423  for (code = first_significant_code(code + _pcre_OP_len Line 2674  for (code = first_significant_code(code + _pcre_OP_len
     case OP_MARK:      case OP_MARK:
     case OP_PRUNE_ARG:      case OP_PRUNE_ARG:
     case OP_SKIP_ARG:      case OP_SKIP_ARG:
     code += code[1];  
     break;  
   
     case OP_THEN_ARG:      case OP_THEN_ARG:
     code += code[1];      code += code[1];
     break;      break;
Line 2457  Arguments: Line 2705  Arguments:
   code        points to start of the recursion    code        points to start of the recursion
   endcode     points to where to stop (current RECURSE item)    endcode     points to where to stop (current RECURSE item)
   bcptr       points to the chain of current (unclosed) branch starts    bcptr       points to the chain of current (unclosed) branch starts
  utf8        TRUE if in UTF-8 mode  utf         TRUE if in UTF-8 / UTF-16 / UTF-32 mode
   cd          pointers to tables etc    cd          pointers to tables etc
   
 Returns:      TRUE if what is matched could be empty  Returns:      TRUE if what is matched could be empty
 */  */
   
 static BOOL  static BOOL
could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr,could_be_empty(const pcre_uchar *code, const pcre_uchar *endcode,
  BOOL utf8, compile_data *cd)  branch_chain *bcptr, BOOL utf, compile_data *cd)
 {  {
 while (bcptr != NULL && bcptr->current_branch >= code)  while (bcptr != NULL && bcptr->current_branch >= code)
   {    {
  if (!could_be_empty_branch(bcptr->current_branch, endcode, utf8, cd))  if (!could_be_empty_branch(bcptr->current_branch, endcode, utf, cd, NULL))
     return FALSE;      return FALSE;
   bcptr = bcptr->outer;    bcptr = bcptr->outer;
   }    }
Line 2479  return TRUE; Line 2727  return TRUE;
   
   
 /*************************************************  /*************************************************
   *        Base opcode of repeated opcodes         *
   *************************************************/
   
   /* Returns the base opcode for repeated single character type opcodes. If the
   opcode is not a repeated character type, it returns with the original value.
   
   Arguments:  c opcode
   Returns:    base opcode for the type
   */
   
   static pcre_uchar
   get_repeat_base(pcre_uchar c)
   {
   return (c > OP_TYPEPOSUPTO)? c :
          (c >= OP_TYPESTAR)?   OP_TYPESTAR :
          (c >= OP_NOTSTARI)?   OP_NOTSTARI :
          (c >= OP_NOTSTAR)?    OP_NOTSTAR :
          (c >= OP_STARI)?      OP_STARI :
                                OP_STAR;
   }
   
   
   
   #ifdef SUPPORT_UCP
   /*************************************************
   *        Check a character and a property        *
   *************************************************/
   
   /* This function is called by check_auto_possessive() when a property item
   is adjacent to a fixed character.
   
   Arguments:
     c            the character
     ptype        the property type
     pdata        the data for the type
     negated      TRUE if it's a negated property (\P or \p{^)
   
   Returns:       TRUE if auto-possessifying is OK
   */
   
   static BOOL
   check_char_prop(pcre_uint32 c, unsigned int ptype, unsigned int pdata,
     BOOL negated)
   {
   const pcre_uint32 *p;
   const ucd_record *prop = GET_UCD(c);
   
   switch(ptype)
     {
     case PT_LAMP:
     return (prop->chartype == ucp_Lu ||
             prop->chartype == ucp_Ll ||
             prop->chartype == ucp_Lt) == negated;
   
     case PT_GC:
     return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
   
     case PT_PC:
     return (pdata == prop->chartype) == negated;
   
     case PT_SC:
     return (pdata == prop->script) == negated;
   
     /* These are specials */
   
     case PT_ALNUM:
     return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
             PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
   
     /* Perl space used to exclude VT, but from Perl 5.18 it is included, which
     means that Perl space and POSIX space are now identical. PCRE was changed
     at release 8.34. */
   
     case PT_SPACE:    /* Perl space */
     case PT_PXSPACE:  /* POSIX space */
     switch(c)
       {
       HSPACE_CASES:
       VSPACE_CASES:
       return negated;
   
       default:
       return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
       }
     break;  /* Control never reaches here */
   
     case PT_WORD:
     return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
             PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
             c == CHAR_UNDERSCORE) == negated;
   
     case PT_CLIST:
     p = PRIV(ucd_caseless_sets) + prop->caseset;
     for (;;)
       {
       if (c < *p) return !negated;
       if (c == *p++) return negated;
       }
     break;  /* Control never reaches here */
     }
   
   return FALSE;
   }
   #endif  /* SUPPORT_UCP */
   
   
   
   /*************************************************
   *        Fill the character property list        *
   *************************************************/
   
   /* Checks whether the code points to an opcode that can take part in auto-
   possessification, and if so, fills a list with its properties.
   
   Arguments:
     code        points to start of expression
     utf         TRUE if in UTF-8 / UTF-16 / UTF-32 mode
     fcc         points to case-flipping table
     list        points to output list
                 list[0] will be filled with the opcode
                 list[1] will be non-zero if this opcode
                   can match an empty character string
                 list[2..7] depends on the opcode
   
   Returns:      points to the start of the next opcode if *code is accepted
                 NULL if *code is not accepted
   */
   
   static const pcre_uchar *
   get_chr_property_list(const pcre_uchar *code, BOOL utf,
     const pcre_uint8 *fcc, pcre_uint32 *list)
   {
   pcre_uchar c = *code;
   pcre_uchar base;
   const pcre_uchar *end;
   pcre_uint32 chr;
   
   #ifdef SUPPORT_UCP
   pcre_uint32 *clist_dest;
   const pcre_uint32 *clist_src;
   #else
   utf = utf;  /* Suppress "unused parameter" compiler warning */
   #endif
   
   list[0] = c;
   list[1] = FALSE;
   code++;
   
   if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
     {
     base = get_repeat_base(c);
     c -= (base - OP_STAR);
   
     if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO)
       code += IMM2_SIZE;
   
     list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT && c != OP_POSPLUS);
   
     switch(base)
       {
       case OP_STAR:
       list[0] = OP_CHAR;
       break;
   
       case OP_STARI:
       list[0] = OP_CHARI;
       break;
   
       case OP_NOTSTAR:
       list[0] = OP_NOT;
       break;
   
       case OP_NOTSTARI:
       list[0] = OP_NOTI;
       break;
   
       case OP_TYPESTAR:
       list[0] = *code;
       code++;
       break;
       }
     c = list[0];
     }
   
   switch(c)
     {
     case OP_NOT_DIGIT:
     case OP_DIGIT:
     case OP_NOT_WHITESPACE:
     case OP_WHITESPACE:
     case OP_NOT_WORDCHAR:
     case OP_WORDCHAR:
     case OP_ANY:
     case OP_ALLANY:
     case OP_ANYNL:
     case OP_NOT_HSPACE:
     case OP_HSPACE:
     case OP_NOT_VSPACE:
     case OP_VSPACE:
     case OP_EXTUNI:
     case OP_EODN:
     case OP_EOD:
     case OP_DOLL:
     case OP_DOLLM:
     return code;
   
     case OP_CHAR:
     case OP_NOT:
     GETCHARINCTEST(chr, code);
     list[2] = chr;
     list[3] = NOTACHAR;
     return code;
   
     case OP_CHARI:
     case OP_NOTI:
     list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT;
     GETCHARINCTEST(chr, code);
     list[2] = chr;
   
   #ifdef SUPPORT_UCP
     if (chr < 128 || (chr < 256 && !utf))
       list[3] = fcc[chr];
     else
       list[3] = UCD_OTHERCASE(chr);
   #elif defined SUPPORT_UTF || !defined COMPILE_PCRE8
     list[3] = (chr < 256) ? fcc[chr] : chr;
   #else
     list[3] = fcc[chr];
   #endif
   
     /* The othercase might be the same value. */
   
     if (chr == list[3])
       list[3] = NOTACHAR;
     else
       list[4] = NOTACHAR;
     return code;
   
   #ifdef SUPPORT_UCP
     case OP_PROP:
     case OP_NOTPROP:
     if (code[0] != PT_CLIST)
       {
       list[2] = code[0];
       list[3] = code[1];
       return code + 2;
       }
   
     /* Convert only if we have enough space. */
   
     clist_src = PRIV(ucd_caseless_sets) + code[1];
     clist_dest = list + 2;
     code += 2;
   
     do {
        if (clist_dest >= list + 8)
          {
          /* Early return if there is not enough space. This should never
          happen, since all clists are shorter than 5 character now. */
          list[2] = code[0];
          list[3] = code[1];
          return code;
          }
        *clist_dest++ = *clist_src;
        }
     while(*clist_src++ != NOTACHAR);
   
     /* All characters are stored. The terminating NOTACHAR
     is copied form the clist itself. */
   
     list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT;
     return code;
   #endif
   
     case OP_NCLASS:
     case OP_CLASS:
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
     case OP_XCLASS:
     if (c == OP_XCLASS)
       end = code + GET(code, 0) - 1;
     else
   #endif
       end = code + 32 / sizeof(pcre_uchar);
   
     switch(*end)
       {
       case OP_CRSTAR:
       case OP_CRMINSTAR:
       case OP_CRQUERY:
       case OP_CRMINQUERY:
       case OP_CRPOSSTAR:
       case OP_CRPOSQUERY:
       list[1] = TRUE;
       end++;
       break;
   
       case OP_CRPLUS:
       case OP_CRMINPLUS:
       case OP_CRPOSPLUS:
       end++;
       break;
   
       case OP_CRRANGE:
       case OP_CRMINRANGE:
       case OP_CRPOSRANGE:
       list[1] = (GET2(end, 1) == 0);
       end += 1 + 2 * IMM2_SIZE;
       break;
       }
     list[2] = end - code;
     return end;
     }
   return NULL;    /* Opcode not accepted */
   }
   
   
   
   /*************************************************
   *    Scan further character sets for match       *
   *************************************************/
   
   /* Checks whether the base and the current opcode have a common character, in
   which case the base cannot be possessified.
   
   Arguments:
     code        points to the byte code
     utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
     cd          static compile data
     base_list   the data list of the base opcode
   
   Returns:      TRUE if the auto-possessification is possible
   */
   
   static BOOL
   compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd,
     const pcre_uint32 *base_list, const pcre_uchar *base_end)
   {
   pcre_uchar c;
   pcre_uint32 list[8];
   const pcre_uint32 *chr_ptr;
   const pcre_uint32 *ochr_ptr;
   const pcre_uint32 *list_ptr;
   const pcre_uchar *next_code;
   const pcre_uint8 *class_bitset;
   const pcre_uint32 *set1, *set2, *set_end;
   pcre_uint32 chr;
   BOOL accepted, invert_bits;
   
   /* Note: the base_list[1] contains whether the current opcode has greedy
   (represented by a non-zero value) quantifier. This is a different from
   other character type lists, which stores here that the character iterator
   matches to an empty string (also represented by a non-zero value). */
   
   for(;;)
     {
     /* All operations move the code pointer forward.
     Therefore infinite recursions are not possible. */
   
     c = *code;
   
     /* Skip over callouts */
   
     if (c == OP_CALLOUT)
       {
       code += PRIV(OP_lengths)[c];
       continue;
       }
   
     if (c == OP_ALT)
       {
       do code += GET(code, 1); while (*code == OP_ALT);
       c = *code;
       }
   
     switch(c)
       {
       case OP_END:
       case OP_KETRPOS:
       /* TRUE only in greedy case. The non-greedy case could be replaced by
       an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT
       uses more memory, which we cannot get at this stage.) */
   
       return base_list[1] != 0;
   
       case OP_KET:
       /* If the bracket is capturing, and referenced by an OP_RECURSE, or
       it is an atomic sub-pattern (assert, once, etc.) the non-greedy case
       cannot be converted to a possessive form. */
   
       if (base_list[1] == 0) return FALSE;
   
       switch(*(code - GET(code, 1)))
         {
         case OP_ASSERT:
         case OP_ASSERT_NOT:
         case OP_ASSERTBACK:
         case OP_ASSERTBACK_NOT:
         case OP_ONCE:
         case OP_ONCE_NC:
         /* Atomic sub-patterns and assertions can always auto-possessify their
         last iterator. */
         return TRUE;
         }
   
       code += PRIV(OP_lengths)[c];
       continue;
   
       case OP_ONCE:
       case OP_ONCE_NC:
       case OP_BRA:
       case OP_CBRA:
       next_code = code + GET(code, 1);
       code += PRIV(OP_lengths)[c];
   
       while (*next_code == OP_ALT)
         {
         if (!compare_opcodes(code, utf, cd, base_list, base_end)) return FALSE;
         code = next_code + 1 + LINK_SIZE;
         next_code += GET(next_code, 1);
         }
       continue;
   
       case OP_BRAZERO:
       case OP_BRAMINZERO:
   
       next_code = code + 1;
       if (*next_code != OP_BRA && *next_code != OP_CBRA
           && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE;
   
       do next_code += GET(next_code, 1); while (*next_code == OP_ALT);
   
       /* The bracket content will be checked by the
       OP_BRA/OP_CBRA case above. */
       next_code += 1 + LINK_SIZE;
       if (!compare_opcodes(next_code, utf, cd, base_list, base_end))
         return FALSE;
   
       code += PRIV(OP_lengths)[c];
       continue;
       }
   
     /* Check for a supported opcode, and load its properties. */
   
     code = get_chr_property_list(code, utf, cd->fcc, list);
     if (code == NULL) return FALSE;    /* Unsupported */
   
     /* If either opcode is a small character list, set pointers for comparing
     characters from that list with another list, or with a property. */
   
     if (base_list[0] == OP_CHAR)
       {
       chr_ptr = base_list + 2;
       list_ptr = list;
       }
     else if (list[0] == OP_CHAR)
       {
       chr_ptr = list + 2;
       list_ptr = base_list;
       }
   
     /* Character bitsets can also be compared to certain opcodes. */
   
     else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS
   #ifdef COMPILE_PCRE8
         /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */
         || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS))
   #endif
         )
       {
   #ifdef COMPILE_PCRE8
       if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS))
   #else
       if (base_list[0] == OP_CLASS)
   #endif
         {
         set1 = (pcre_uint32 *)(base_end - base_list[2]);
         list_ptr = list;
         }
       else
         {
         set1 = (pcre_uint32 *)(code - list[2]);
         list_ptr = base_list;
         }
   
       invert_bits = FALSE;
       switch(list_ptr[0])
         {
         case OP_CLASS:
         case OP_NCLASS:
         set2 = (pcre_uint32 *)
           ((list_ptr == list ? code : base_end) - list_ptr[2]);
         break;
   
         /* OP_XCLASS cannot be supported here, because its bitset
         is not necessarily complete. E.g: [a-\0x{200}] is stored
         as a character range, and the appropriate bits are not set. */
   
         case OP_NOT_DIGIT:
           invert_bits = TRUE;
           /* Fall through */
         case OP_DIGIT:
           set2 = (pcre_uint32 *)(cd->cbits + cbit_digit);
           break;
   
         case OP_NOT_WHITESPACE:
           invert_bits = TRUE;
           /* Fall through */
         case OP_WHITESPACE:
           set2 = (pcre_uint32 *)(cd->cbits + cbit_space);
           break;
   
         case OP_NOT_WORDCHAR:
           invert_bits = TRUE;
           /* Fall through */
         case OP_WORDCHAR:
           set2 = (pcre_uint32 *)(cd->cbits + cbit_word);
           break;
   
         default:
         return FALSE;
         }
   
       /* Compare 4 bytes to improve speed. */
       set_end = set1 + (32 / 4);
       if (invert_bits)
         {
         do
           {
           if ((*set1++ & ~(*set2++)) != 0) return FALSE;
           }
         while (set1 < set_end);
         }
       else
         {
         do
           {
           if ((*set1++ & *set2++) != 0) return FALSE;
           }
         while (set1 < set_end);
         }
   
       if (list[1] == 0) return TRUE;
       /* Might be an empty repeat. */
       continue;
       }
   
     /* Some property combinations also acceptable. Unicode property opcodes are
     processed specially; the rest can be handled with a lookup table. */
   
     else
       {
       pcre_uint32 leftop, rightop;
   
       leftop = base_list[0];
       rightop = list[0];
   
   #ifdef SUPPORT_UCP
       accepted = FALSE; /* Always set in non-unicode case. */
       if (leftop == OP_PROP || leftop == OP_NOTPROP)
         {
         if (rightop == OP_EOD)
           accepted = TRUE;
         else if (rightop == OP_PROP || rightop == OP_NOTPROP)
           {
           int n;
           const pcre_uint8 *p;
           BOOL same = leftop == rightop;
           BOOL lisprop = leftop == OP_PROP;
           BOOL risprop = rightop == OP_PROP;
           BOOL bothprop = lisprop && risprop;
   
           /* There's a table that specifies how each combination is to be
           processed:
             0   Always return FALSE (never auto-possessify)
             1   Character groups are distinct (possessify if both are OP_PROP)
             2   Check character categories in the same group (general or particular)
             3   Return TRUE if the two opcodes are not the same
             ... see comments below
           */
   
           n = propposstab[base_list[2]][list[2]];
           switch(n)
             {
             case 0: break;
             case 1: accepted = bothprop; break;
             case 2: accepted = (base_list[3] == list[3]) != same; break;
             case 3: accepted = !same; break;
   
             case 4:  /* Left general category, right particular category */
             accepted = risprop && catposstab[base_list[3]][list[3]] == same;
             break;
   
             case 5:  /* Right general category, left particular category */
             accepted = lisprop && catposstab[list[3]][base_list[3]] == same;
             break;
   
             /* This code is logically tricky. Think hard before fiddling with it.
             The posspropstab table has four entries per row. Each row relates to
             one of PCRE's special properties such as ALNUM or SPACE or WORD.
             Only WORD actually needs all four entries, but using repeats for the
             others means they can all use the same code below.
   
             The first two entries in each row are Unicode general categories, and
             apply always, because all the characters they include are part of the
             PCRE character set. The third and fourth entries are a general and a
             particular category, respectively, that include one or more relevant
             characters. One or the other is used, depending on whether the check
             is for a general or a particular category. However, in both cases the
             category contains more characters than the specials that are defined
             for the property being tested against. Therefore, it cannot be used
             in a NOTPROP case.
   
             Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po.
             Underscore is covered by ucp_P or ucp_Po. */
   
             case 6:  /* Left alphanum vs right general category */
             case 7:  /* Left space vs right general category */
             case 8:  /* Left word vs right general category */
             p = posspropstab[n-6];
             accepted = risprop && lisprop ==
               (list[3] != p[0] &&
                list[3] != p[1] &&
               (list[3] != p[2] || !lisprop));
             break;
   
             case 9:   /* Right alphanum vs left general category */
             case 10:  /* Right space vs left general category */
             case 11:  /* Right word vs left general category */
             p = posspropstab[n-9];
             accepted = lisprop && risprop ==
               (base_list[3] != p[0] &&
                base_list[3] != p[1] &&
               (base_list[3] != p[2] || !risprop));
             break;
   
             case 12:  /* Left alphanum vs right particular category */
             case 13:  /* Left space vs right particular category */
             case 14:  /* Left word vs right particular category */
             p = posspropstab[n-12];
             accepted = risprop && lisprop ==
               (catposstab[p[0]][list[3]] &&
                catposstab[p[1]][list[3]] &&
               (list[3] != p[3] || !lisprop));
             break;
   
             case 15:  /* Right alphanum vs left particular category */
             case 16:  /* Right space vs left particular category */
             case 17:  /* Right word vs left particular category */
             p = posspropstab[n-15];
             accepted = lisprop && risprop ==
               (catposstab[p[0]][base_list[3]] &&
                catposstab[p[1]][base_list[3]] &&
               (base_list[3] != p[3] || !risprop));
             break;
             }
           }
         }
   
       else
   #endif  /* SUPPORT_UCP */
   
       accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP &&
              rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP &&
              autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP];
   
       if (!accepted)
         return FALSE;
   
       if (list[1] == 0) return TRUE;
       /* Might be an empty repeat. */
       continue;
       }
   
     /* Control reaches here only if one of the items is a small character list.
     All characters are checked against the other side. */
   
     do
       {
       chr = *chr_ptr;
   
       switch(list_ptr[0])
         {
         case OP_CHAR:
         ochr_ptr = list_ptr + 2;
         do
           {
           if (chr == *ochr_ptr) return FALSE;
           ochr_ptr++;
           }
         while(*ochr_ptr != NOTACHAR);
         break;
   
         case OP_NOT:
         ochr_ptr = list_ptr + 2;
         do
           {
           if (chr == *ochr_ptr)
             break;
           ochr_ptr++;
           }
         while(*ochr_ptr != NOTACHAR);
         if (*ochr_ptr == NOTACHAR) return FALSE;   /* Not found */
         break;
   
         /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not*
         set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
   
         case OP_DIGIT:
         if (chr < 256 && (cd->ctypes[chr] & ctype_digit) != 0) return FALSE;
         break;
   
         case OP_NOT_DIGIT:
         if (chr > 255 || (cd->ctypes[chr] & ctype_digit) == 0) return FALSE;
         break;
   
         case OP_WHITESPACE:
         if (chr < 256 && (cd->ctypes[chr] & ctype_space) != 0) return FALSE;
         break;
   
         case OP_NOT_WHITESPACE:
         if (chr > 255 || (cd->ctypes[chr] & ctype_space) == 0) return FALSE;
         break;
   
         case OP_WORDCHAR:
         if (chr < 255 && (cd->ctypes[chr] & ctype_word) != 0) return FALSE;
         break;
   
         case OP_NOT_WORDCHAR:
         if (chr > 255 || (cd->ctypes[chr] & ctype_word) == 0) return FALSE;
         break;
   
         case OP_HSPACE:
         switch(chr)
           {
           HSPACE_CASES: return FALSE;
           default: break;
           }
         break;
   
         case OP_NOT_HSPACE:
         switch(chr)
           {
           HSPACE_CASES: break;
           default: return FALSE;
           }
         break;
   
         case OP_ANYNL:
         case OP_VSPACE:
         switch(chr)
           {
           VSPACE_CASES: return FALSE;
           default: break;
           }
         break;
   
         case OP_NOT_VSPACE:
         switch(chr)
           {
           VSPACE_CASES: break;
           default: return FALSE;
           }
         break;
   
         case OP_DOLL:
         case OP_EODN:
         switch (chr)
           {
           case CHAR_CR:
           case CHAR_LF:
           case CHAR_VT:
           case CHAR_FF:
           case CHAR_NEL:
   #ifndef EBCDIC
           case 0x2028:
           case 0x2029:
   #endif  /* Not EBCDIC */
           return FALSE;
           }
         break;
   
         case OP_EOD:    /* Can always possessify before \z */
         break;
   
   #ifdef SUPPORT_UCP
         case OP_PROP:
         case OP_NOTPROP:
         if (!check_char_prop(chr, list_ptr[2], list_ptr[3],
               list_ptr[0] == OP_NOTPROP))
           return FALSE;
         break;
   #endif
   
         case OP_NCLASS:
         if (chr > 255) return FALSE;
         /* Fall through */
   
         case OP_CLASS:
         if (chr > 255) break;
         class_bitset = (pcre_uint8 *)
           ((list_ptr == list ? code : base_end) - list_ptr[2]);
         if ((class_bitset[chr >> 3] & (1 << (chr & 7))) != 0) return FALSE;
         break;
   
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
         case OP_XCLASS:
         if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) -
             list_ptr[2] + LINK_SIZE, utf)) return FALSE;
         break;
   #endif
   
         default:
         return FALSE;
         }
   
       chr_ptr++;
       }
     while(*chr_ptr != NOTACHAR);
   
     /* At least one character must be matched from this opcode. */
   
     if (list[1] == 0) return TRUE;
     }
   
   return FALSE;
   }
   
   
   
   /*************************************************
   *    Scan compiled regex for auto-possession     *
   *************************************************/
   
   /* Replaces single character iterations with their possessive alternatives
   if appropriate. This function modifies the compiled opcode!
   
   Arguments:
     code        points to start of the byte code
     utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
     cd          static compile data
   
   Returns:      nothing
   */
   
   static void
   auto_possessify(pcre_uchar *code, BOOL utf, const compile_data *cd)
   {
   register pcre_uchar c;
   const pcre_uchar *end;
   pcre_uchar *repeat_opcode;
   pcre_uint32 list[8];
   
   for (;;)
     {
     c = *code;
   
     if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
       {
       c -= get_repeat_base(c) - OP_STAR;
       end = (c <= OP_MINUPTO) ?
         get_chr_property_list(code, utf, cd->fcc, list) : NULL;
       list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
   
       if (end != NULL && compare_opcodes(end, utf, cd, list, end))
         {
         switch(c)
           {
           case OP_STAR:
           *code += OP_POSSTAR - OP_STAR;
           break;
   
           case OP_MINSTAR:
           *code += OP_POSSTAR - OP_MINSTAR;
           break;
   
           case OP_PLUS:
           *code += OP_POSPLUS - OP_PLUS;
           break;
   
           case OP_MINPLUS:
           *code += OP_POSPLUS - OP_MINPLUS;
           break;
   
           case OP_QUERY:
           *code += OP_POSQUERY - OP_QUERY;
           break;
   
           case OP_MINQUERY:
           *code += OP_POSQUERY - OP_MINQUERY;
           break;
   
           case OP_UPTO:
           *code += OP_POSUPTO - OP_UPTO;
           break;
   
           case OP_MINUPTO:
           *code += OP_MINUPTO - OP_UPTO;
           break;
           }
         }
       c = *code;
       }
     else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS)
       {
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
       if (c == OP_XCLASS)
         repeat_opcode = code + GET(code, 1);
       else
   #endif
         repeat_opcode = code + 1 + (32 / sizeof(pcre_uchar));
   
       c = *repeat_opcode;
       if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
         {
         /* end must not be NULL. */
         end = get_chr_property_list(code, utf, cd->fcc, list);
   
         list[1] = (c & 1) == 0;
   
         if (compare_opcodes(end, utf, cd, list, end))
           {
           switch (c)
             {
             case OP_CRSTAR:
             case OP_CRMINSTAR:
             *repeat_opcode = OP_CRPOSSTAR;
             break;
   
             case OP_CRPLUS:
             case OP_CRMINPLUS:
             *repeat_opcode = OP_CRPOSPLUS;
             break;
   
             case OP_CRQUERY:
             case OP_CRMINQUERY:
             *repeat_opcode = OP_CRPOSQUERY;
             break;
   
             case OP_CRRANGE:
             case OP_CRMINRANGE:
             *repeat_opcode = OP_CRPOSRANGE;
             break;
             }
           }
         }
       c = *code;
       }
   
     switch(c)
       {
       case OP_END:
       return;
   
       case OP_TYPESTAR:
       case OP_TYPEMINSTAR:
       case OP_TYPEPLUS:
       case OP_TYPEMINPLUS:
       case OP_TYPEQUERY:
       case OP_TYPEMINQUERY:
       case OP_TYPEPOSSTAR:
       case OP_TYPEPOSPLUS:
       case OP_TYPEPOSQUERY:
       if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
       break;
   
       case OP_TYPEUPTO:
       case OP_TYPEMINUPTO:
       case OP_TYPEEXACT:
       case OP_TYPEPOSUPTO:
       if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
         code += 2;
       break;
   
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
       case OP_XCLASS:
       code += GET(code, 1);
       break;
   #endif
   
       case OP_MARK:
       case OP_PRUNE_ARG:
       case OP_SKIP_ARG:
       case OP_THEN_ARG:
       code += code[1];
       break;
       }
   
     /* Add in the fixed length from the table */
   
     code += PRIV(OP_lengths)[c];
   
     /* In UTF-8 mode, opcodes that are followed by a character may be followed by
     a multi-byte character. The length in the table is a minimum, so we have to
     arrange to skip the extra bytes. */
   
   #if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     if (utf) switch(c)
       {
       case OP_CHAR:
       case OP_CHARI:
       case OP_NOT:
       case OP_NOTI:
       case OP_STAR:
       case OP_MINSTAR:
       case OP_PLUS:
       case OP_MINPLUS:
       case OP_QUERY:
       case OP_MINQUERY:
       case OP_UPTO:
       case OP_MINUPTO:
       case OP_EXACT:
       case OP_POSSTAR:
       case OP_POSPLUS:
       case OP_POSQUERY:
       case OP_POSUPTO:
       case OP_STARI:
       case OP_MINSTARI:
       case OP_PLUSI:
       case OP_MINPLUSI:
       case OP_QUERYI:
       case OP_MINQUERYI:
       case OP_UPTOI:
       case OP_MINUPTOI:
       case OP_EXACTI:
       case OP_POSSTARI:
       case OP_POSPLUSI:
       case OP_POSQUERYI:
       case OP_POSUPTOI:
       case OP_NOTSTAR:
       case OP_NOTMINSTAR:
       case OP_NOTPLUS:
       case OP_NOTMINPLUS:
       case OP_NOTQUERY:
       case OP_NOTMINQUERY:
       case OP_NOTUPTO:
       case OP_NOTMINUPTO:
       case OP_NOTEXACT:
       case OP_NOTPOSSTAR:
       case OP_NOTPOSPLUS:
       case OP_NOTPOSQUERY:
       case OP_NOTPOSUPTO:
       case OP_NOTSTARI:
       case OP_NOTMINSTARI:
       case OP_NOTPLUSI:
       case OP_NOTMINPLUSI:
       case OP_NOTQUERYI:
       case OP_NOTMINQUERYI:
       case OP_NOTUPTOI:
       case OP_NOTMINUPTOI:
       case OP_NOTEXACTI:
       case OP_NOTPOSSTARI:
       case OP_NOTPOSPLUSI:
       case OP_NOTPOSQUERYI:
       case OP_NOTPOSUPTOI:
       if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
       break;
       }
   #else
     (void)(utf);  /* Keep compiler happy by referencing function argument */
   #endif
     }
   }
   
   
   
   /*************************************************
 *           Check for POSIX class syntax         *  *           Check for POSIX class syntax         *
 *************************************************/  *************************************************/
   
Line 2499  class, but [abc[:x\]pqr:]] is (so that an error can be Line 3813  class, but [abc[:x\]pqr:]] is (so that an error can be
 below handles the special case of \], but does not try to do any other escape  below handles the special case of \], but does not try to do any other escape
 processing. This makes it different from Perl for cases such as [:l\ower:]  processing. This makes it different from Perl for cases such as [:l\ower:]
 where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize  where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize
"l\ower". This is a lesser evil that not diagnosing bad classes when Perl does,"l\ower". This is a lesser evil than not diagnosing bad classes when Perl does,
 I think.  I think.
   
 A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.  A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.
Line 2521  Returns:   TRUE or FALSE Line 3835  Returns:   TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
check_posix_syntax(const uschar *ptr, const uschar **endptr)check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr)
 {  {
int terminator;          /* Don't combine these lines; the Solaris cc */pcre_uchar terminator;          /* Don't combine these lines; the Solaris cc */
 terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */  terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
for (++ptr; *ptr != 0; ptr++)for (++ptr; *ptr != CHAR_NULL; ptr++)
   {    {
   if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)    if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
     ptr++;      ptr++;
Line 2565  Returns:     a value representing the name, or -1 if u Line 3879  Returns:     a value representing the name, or -1 if u
 */  */
   
 static int  static int
check_posix_name(const uschar *ptr, int len)check_posix_name(const pcre_uchar *ptr, int len)
 {  {
 const char *pn = posix_names;  const char *pn = posix_names;
 register int yield = 0;  register int yield = 0;
 while (posix_name_lengths[yield] != 0)  while (posix_name_lengths[yield] != 0)
   {    {
   if (len == posix_name_lengths[yield] &&    if (len == posix_name_lengths[yield] &&
    strncmp((const char *)ptr, pn, len) == 0) return yield;    STRNCMP_UC_C8(ptr, pn, (unsigned int)len) == 0) return yield;
   pn += posix_name_lengths[yield] + 1;    pn += posix_name_lengths[yield] + 1;
   yield++;    yield++;
   }    }
Line 2604  value in the reference (which is a group number). Line 3918  value in the reference (which is a group number).
 Arguments:  Arguments:
   group      points to the start of the group    group      points to the start of the group
   adjust     the amount by which the group is to be moved    adjust     the amount by which the group is to be moved
  utf8       TRUE in UTF-8 mode  utf        TRUE in UTF-8 / UTF-16 / UTF-32 mode
   cd         contains pointers to tables etc.    cd         contains pointers to tables etc.
   save_hwm   the hwm forward reference pointer at the start of the group    save_hwm   the hwm forward reference pointer at the start of the group
   
Line 2612  Returns:     nothing Line 3926  Returns:     nothing
 */  */
   
 static void  static void
adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd,adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
  uschar *save_hwm)  pcre_uchar *save_hwm)
 {  {
uschar *ptr = group;pcre_uchar *ptr = group;
   
while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL)while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
   {    {
   int offset;    int offset;
  uschar *hc;  pcre_uchar *hc;
   
   /* See if this recursion is on the forward reference list. If so, adjust the    /* See if this recursion is on the forward reference list. If so, adjust the
   reference. */    reference. */
   
   for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)    for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
     {      {
    offset = GET(hc, 0);    offset = (int)GET(hc, 0);
     if (cd->start_code + offset == ptr + 1)      if (cd->start_code + offset == ptr + 1)
       {        {
       PUT(hc, 0, offset + adjust);        PUT(hc, 0, offset + adjust);
Line 2640  while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NU Line 3954  while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NU
   
   if (hc >= cd->hwm)    if (hc >= cd->hwm)
     {      {
    offset = GET(ptr, 1);    offset = (int)GET(ptr, 1);
     if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);      if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);
     }      }
   
Line 2665  Arguments: Line 3979  Arguments:
 Returns:         new code pointer  Returns:         new code pointer
 */  */
   
static uschar *static pcre_uchar *
auto_callout(uschar *code, const uschar *ptr, compile_data *cd)auto_callout(pcre_uchar *code, const pcre_uchar *ptr, compile_data *cd)
 {  {
 *code++ = OP_CALLOUT;  *code++ = OP_CALLOUT;
 *code++ = 255;  *code++ = 255;
 PUT(code, 0, (int)(ptr - cd->start_pattern));  /* Pattern offset */  PUT(code, 0, (int)(ptr - cd->start_pattern));  /* Pattern offset */
 PUT(code, LINK_SIZE, 0);                       /* Default length */  PUT(code, LINK_SIZE, 0);                       /* Default length */
return code + 2*LINK_SIZE;return code + 2 * LINK_SIZE;
 }  }
   
   
Line 2694  Returns:             nothing Line 4008  Returns:             nothing
 */  */
   
 static void  static void
complete_callout(uschar *previous_callout, const uschar *ptr, compile_data *cd)complete_callout(pcre_uchar *previous_callout, const pcre_uchar *ptr, compile_data *cd)
 {  {
 int length = (int)(ptr - cd->start_pattern - GET(previous_callout, 2));  int length = (int)(ptr - cd->start_pattern - GET(previous_callout, 2));
 PUT(previous_callout, 2 + LINK_SIZE, length);  PUT(previous_callout, 2 + LINK_SIZE, length);
Line 2708  PUT(previous_callout, 2 + LINK_SIZE, length); Line 4022  PUT(previous_callout, 2 + LINK_SIZE, length);
 *************************************************/  *************************************************/
   
 /* This function is passed the start and end of a class range, in UTF-8 mode  /* This function is passed the start and end of a class range, in UTF-8 mode
with UCP support. It searches up the characters, looking for internal ranges ofwith UCP support. It searches up the characters, looking for ranges of
 characters in the "other" case. Each call returns the next one, updating the  characters in the "other" case. Each call returns the next one, updating the
start address.start address. A character with multiple other cases is returned on its own
 with a special return value.
   
 Arguments:  Arguments:
   cptr        points to starting character value; updated    cptr        points to starting character value; updated
Line 2718  Arguments: Line 4033  Arguments:
   ocptr       where to put start of othercase range    ocptr       where to put start of othercase range
   odptr       where to put end of othercase range    odptr       where to put end of othercase range
   
Yield:        TRUE when range returned; FALSE when no moreYield:        -1 when no more
                0 when a range is returned
               >0 the CASESET offset for char with multiple other cases
                 in this case, ocptr contains the original
 */  */
   
static BOOLstatic int
get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr,get_othercase_range(pcre_uint32 *cptr, pcre_uint32 d, pcre_uint32 *ocptr,
  unsigned int *odptr)  pcre_uint32 *odptr)
 {  {
unsigned int c, othercase, next;pcre_uint32 c, othercase, next;
 unsigned int co;
   
   /* Find the first character that has an other case. If it has multiple other
   cases, return its case offset value. */
   
 for (c = *cptr; c <= d; c++)  for (c = *cptr; c <= d; c++)
  { if ((othercase = UCD_OTHERCASE(c)) != c) break; }  {
   if ((co = UCD_CASESET(c)) != 0)
     {
     *ocptr = c++;   /* Character that has the set */
     *cptr = c;      /* Rest of input range */
     return (int)co;
     }
   if ((othercase = UCD_OTHERCASE(c)) != c) break;
   }
   
if (c > d) return FALSE;if (c > d) return -1;  /* Reached end of range */
   
 *ocptr = othercase;  *ocptr = othercase;
 next = othercase + 1;  next = othercase + 1;
Line 2741  for (++c; c <= d; c++) Line 4071  for (++c; c <= d; c++)
   next++;    next++;
   }    }
   
*odptr = next - 1;*odptr = next - 1;     /* End of othercase range */
*cptr = c;*cptr = c;             /* Rest of input range */
return 0;
return TRUE; 
 }  }
   #endif  /* SUPPORT_UCP */
   
   
   
 /*************************************************  /*************************************************
*        Check a character and a property        **        Add a character or range to a class     *
 *************************************************/  *************************************************/
   
/* This function is called by check_auto_possessive() when a property item/* This function packages up the logic of adding a character or range of
is adjacent to a fixed character.characters to a class. The character values in the arguments will be within the
 valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
 mutually recursive with the function immediately below.
   
 Arguments:  Arguments:
  c            the character  classbits     the bit map for characters < 256
  ptype        the property type  uchardptr     points to the pointer for extra data
  pdata        the data for the type  options       the options word
  negated      TRUE if it's a negated property (\P or \p{^)  cd            contains pointers to tables etc.
   start         start of range character
   end           end of range character
   
Returns:       TRUE if auto-possessifying is OKReturns:        the number of < 256 characters added
                 the pointer to extra data is updated
 */  */
   
static BOOLstatic int
check_char_prop(int c, int ptype, int pdata, BOOL negated)add_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
   compile_data *cd, pcre_uint32 start, pcre_uint32 end)
 {  {
const ucd_record *prop = GET_UCD(c);pcre_uint32 c;
switch(ptype)int n8 = 0;
  { 
  case PT_LAMP: 
  return (prop->chartype == ucp_Lu || 
          prop->chartype == ucp_Ll || 
          prop->chartype == ucp_Lt) == negated; 
   
  case PT_GC:/* If caseless matching is required, scan the range and process alternate
  return (pdata == _pcre_ucp_gentype[prop->chartype]) == negated;cases. In Unicode, there are 8-bit characters that have alternate cases that
 are greater than 255 and vice-versa. Sometimes we can just extend the original
 range. */
   
  case PT_PC:if ((options & PCRE_CASELESS) != 0)
  return (pdata == prop->chartype) == negated;  {
 #ifdef SUPPORT_UCP
   if ((options & PCRE_UTF8) != 0)
     {
     int rc;
     pcre_uint32 oc, od;
   
  case PT_SC:    options &= ~PCRE_CASELESS;   /* Remove for recursive calls */
  return (pdata == prop->script) == negated;    c = start;
   
  /* These are specials */    while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
       {
       /* Handle a single character that has more than one other case. */
   
  case PT_ALNUM:      if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cd,
  return (_pcre_ucp_gentype[prop->chartype] == ucp_L ||        PRIV(ucd_caseless_sets) + rc, oc);
          _pcre_ucp_gentype[prop->chartype] == ucp_N) == negated; 
   
  case PT_SPACE:    /* Perl space */      /* Do nothing if the other case range is within the original range. */
  return (_pcre_ucp_gentype[prop->chartype] == ucp_Z || 
          c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR) 
          == negated; 
   
  case PT_PXSPACE:  /* POSIX space */      else if (oc >= start && od <= end) continue;
  return (_pcre_ucp_gentype[prop->chartype] == ucp_Z || 
          c == CHAR_HT || c == CHAR_NL || c == CHAR_VT || 
          c == CHAR_FF || c == CHAR_CR) 
          == negated; 
   
  case PT_WORD:      /* Extend the original range if there is overlap, noting that if oc < c, we
  return (_pcre_ucp_gentype[prop->chartype] == ucp_L ||      can't have od > end because a subrange is always shorter than the basic
          _pcre_ucp_gentype[prop->chartype] == ucp_N ||      range. Otherwise, use a recursive call to add the additional range. */
          c == CHAR_UNDERSCORE) == negated;
  }      else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
return FALSE;      else if (od > end && oc <= end + 1) end = od;       /* Extend upwards */
}      else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od);
       }
     }
   else
 #endif  /* SUPPORT_UCP */  #endif  /* SUPPORT_UCP */
   
     /* Not UTF-mode, or no UCP */
   
  for (c = start; c <= end && c < 256; c++)
/************************************************* 
*     Check if auto-possessifying is possible    * 
*************************************************/ 
 
/* This function is called for unlimited repeats of certain items, to see 
whether the next thing could possibly match the repeated item. If not, it makes 
sense to automatically possessify the repeated item. 
 
Arguments: 
  previous      pointer to the repeated opcode 
  utf8          TRUE in UTF-8 mode 
  ptr           next character in pattern 
  options       options bits 
  cd            contains pointers to tables etc. 
 
Returns:        TRUE if possessifying is wanted 
*/ 
 
static BOOL 
check_auto_possessive(const uschar *previous, BOOL utf8, const uschar *ptr, 
  int options, compile_data *cd) 
{ 
int c, next; 
int op_code = *previous++; 
 
/* Skip whitespace and comments in extended mode */ 
 
if ((options & PCRE_EXTENDED) != 0) 
  { 
  for (;;) 
     {      {
    while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++;    SETBIT(classbits, cd->fcc[c]);
    if (*ptr == CHAR_NUMBER_SIGN)    n8++;
      { 
      ptr++; 
      while (*ptr != 0) 
        { 
        if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } 
        ptr++; 
#ifdef SUPPORT_UTF8 
        if (utf8) while ((*ptr & 0xc0) == 0x80) ptr++; 
#endif 
        } 
      } 
    else break; 
     }      }
   }    }
   
/* If the next item is one that we can handle, get its value. A non-negative/* Now handle the original range. Adjust the final value according to the bit
value is a character, a negative value is an escape value. */length - this means that the same lists of (e.g.) horizontal spaces can be used
 in all cases. */
   
if (*ptr == CHAR_BACKSLASH)#if defined COMPILE_PCRE8
  {#ifdef SUPPORT_UTF
  int temperrorcode = 0;  if ((options & PCRE_UTF8) == 0)
  next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE);#endif
  if (temperrorcode != 0) return FALSE;  if (end > 0xff) end = 0xff;
  ptr++;    /* Point after the escape sequence */ 
  } 
   
else if ((cd->ctypes[*ptr] & ctype_meta) == 0)#elif defined COMPILE_PCRE16
  {#ifdef SUPPORT_UTF
#ifdef SUPPORT_UTF8  if ((options & PCRE_UTF16) == 0)
  if (utf8) { GETCHARINC(next, ptr); } else 
 #endif  #endif
  next = *ptr++;  if (end > 0xffff) end = 0xffff;
  } 
   
else return FALSE;#endif /* COMPILE_PCRE[8|16] */
   
/* Skip whitespace and comments in extended mode *//* If all characters are less than 256, use the bit map. Otherwise use extra
 data. */
   
if ((options & PCRE_EXTENDED) != 0)if (end < 0x100)
   {    {
  for (;;)  for (c = start; c <= end; c++)
     {      {
    while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++;    n8++;
    if (*ptr == CHAR_NUMBER_SIGN)    SETBIT(classbits, c);
      { 
      ptr++; 
      while (*ptr != 0) 
        { 
        if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } 
        ptr++; 
#ifdef SUPPORT_UTF8 
        if (utf8) while ((*ptr & 0xc0) == 0x80) ptr++; 
#endif 
        } 
      } 
    else break; 
     }      }
   }    }
   
/* If the next thing is itself optional, we have to give up. */else
 
if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK || 
  strncmp((char *)ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0) 
    return FALSE; 
 
/* Now compare the next item with the previous opcode. First, handle cases when 
the next item is a character. */ 
 
if (next >= 0) switch(op_code) 
   {    {
  case OP_CHAR:  pcre_uchar *uchardata = *uchardptr;
#ifdef SUPPORT_UTF8 
  GETCHARTEST(c, previous); 
#else 
  c = *previous; 
#endif 
  return c != next; 
   
  /* For CHARI (caseless character) we must check the other case. If we have#ifdef SUPPORT_UTF
  Unicode property support, we can use it to test the other case of  if ((options & PCRE_UTF8) != 0)  /* All UTFs use the same flag bit */
  high-valued characters. */ 
 
  case OP_CHARI: 
#ifdef SUPPORT_UTF8 
  GETCHARTEST(c, previous); 
#else 
  c = *previous; 
#endif 
  if (c == next) return FALSE; 
#ifdef SUPPORT_UTF8 
  if (utf8) 
     {      {
    unsigned int othercase;    if (start < end)
    if (next < 128) othercase = cd->fcc[next]; else      {
#ifdef SUPPORT_UCP      *uchardata++ = XCL_RANGE;
    othercase = UCD_OTHERCASE((unsigned int)next);      uchardata += PRIV(ord2utf)(start, uchardata);
#else      uchardata += PRIV(ord2utf)(end, uchardata);
    othercase = NOTACHAR;      }
#endif    else if (start == end)
    return (unsigned int)c != othercase;      {
       *uchardata++ = XCL_SINGLE;
       uchardata += PRIV(ord2utf)(start, uchardata);
       }
     }      }
   else    else
#endif  /* SUPPORT_UTF8 */#endif  /* SUPPORT_UTF */
  return (c != cd->fcc[next]);  /* Non-UTF-8 mode */ 
   
  /* For OP_NOT and OP_NOTI, the data is always a single-byte character. These  /* Without UTF support, character values are constrained by the bit length,
  opcodes are not used for multi-byte characters, because they are coded using  and can only be > 256 for 16-bit and 32-bit libraries. */
  an XCLASS instead. */ 
   
  case OP_NOT:#ifdef COMPILE_PCRE8
  return (c = *previous) == next;    {}
 
  case OP_NOTI: 
  if ((c = *previous) == next) return TRUE; 
#ifdef SUPPORT_UTF8 
  if (utf8) 
    { 
    unsigned int othercase; 
    if (next < 128) othercase = cd->fcc[next]; else 
#ifdef SUPPORT_UCP 
    othercase = UCD_OTHERCASE(next); 
 #else  #else
    othercase = NOTACHAR;  if (start < end)
#endif 
    return (unsigned int)c == othercase; 
    } 
  else 
#endif  /* SUPPORT_UTF8 */ 
  return (c == cd->fcc[next]);  /* Non-UTF-8 mode */ 
 
  /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* set. 
  When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ 
 
  case OP_DIGIT: 
  return next > 127 || (cd->ctypes[next] & ctype_digit) == 0; 
 
  case OP_NOT_DIGIT: 
  return next <= 127 && (cd->ctypes[next] & ctype_digit) != 0; 
 
  case OP_WHITESPACE: 
  return next > 127 || (cd->ctypes[next] & ctype_space) == 0; 
 
  case OP_NOT_WHITESPACE: 
  return next <= 127 && (cd->ctypes[next] & ctype_space) != 0; 
 
  case OP_WORDCHAR: 
  return next > 127 || (cd->ctypes[next] & ctype_word) == 0; 
 
  case OP_NOT_WORDCHAR: 
  return next <= 127 && (cd->ctypes[next] & ctype_word) != 0; 
 
  case OP_HSPACE: 
  case OP_NOT_HSPACE: 
  switch(next) 
     {      {
    case 0x09:    *uchardata++ = XCL_RANGE;
    case 0x20:    *uchardata++ = start;
    case 0xa0:    *uchardata++ = end;
    case 0x1680: 
    case 0x180e: 
    case 0x2000: 
    case 0x2001: 
    case 0x2002: 
    case 0x2003: 
    case 0x2004: 
    case 0x2005: 
    case 0x2006: 
    case 0x2007: 
    case 0x2008: 
    case 0x2009: 
    case 0x200A: 
    case 0x202f: 
    case 0x205f: 
    case 0x3000: 
    return op_code == OP_NOT_HSPACE; 
    default: 
    return op_code != OP_NOT_HSPACE; 
     }      }
  else if (start == end)
  case OP_ANYNL: 
  case OP_VSPACE: 
  case OP_NOT_VSPACE: 
  switch(next) 
     {      {
    case 0x0a:    *uchardata++ = XCL_SINGLE;
    case 0x0b:    *uchardata++ = start;
    case 0x0c: 
    case 0x0d: 
    case 0x85: 
    case 0x2028: 
    case 0x2029: 
    return op_code == OP_NOT_VSPACE; 
    default: 
    return op_code != OP_NOT_VSPACE; 
     }      }
   
 #ifdef SUPPORT_UCP  
   case OP_PROP:  
   return check_char_prop(next, previous[0], previous[1], FALSE);  
   
   case OP_NOTPROP:  
   return check_char_prop(next, previous[0], previous[1], TRUE);  
 #endif  #endif
   
  default:  *uchardptr = uchardata;   /* Updata extra data pointer */
  return FALSE; 
   }    }
   
   return n8;    /* Number of 8-bit characters */
   }
   
 /* Handle the case when the next item is \d, \s, etc. Note that when PCRE_UCP  
 is set, \d turns into ESC_du rather than ESC_d, etc., so ESC_d etc. are  
 generated only when PCRE_UCP is *not* set, that is, when only ASCII  
 characteristics are recognized. Similarly, the opcodes OP_DIGIT etc. are  
 replaced by OP_PROP codes when PCRE_UCP is set. */  
   
 switch(op_code)  
   {  
   case OP_CHAR:  
   case OP_CHARI:  
 #ifdef SUPPORT_UTF8  
   GETCHARTEST(c, previous);  
 #else  
   c = *previous;  
 #endif  
   switch(-next)  
     {  
     case ESC_d:  
     return c > 127 || (cd->ctypes[c] & ctype_digit) == 0;  
   
     case ESC_D:  
     return c <= 127 && (cd->ctypes[c] & ctype_digit) != 0;  
   
    case ESC_s:/*************************************************
    return c > 127 || (cd->ctypes[c] & ctype_space) == 0;*        Add a list of characters to a class     *
 *************************************************/
   
    case ESC_S:/* This function is used for adding a list of case-equivalent characters to a
    return c <= 127 && (cd->ctypes[c] & ctype_space) != 0;class, and also for adding a list of horizontal or vertical whitespace. If the
 list is in order (which it should be), ranges of characters are detected and
 handled appropriately. This function is mutually recursive with the function
 above.
   
    case ESC_w:Arguments:
    return c > 127 || (cd->ctypes[c] & ctype_word) == 0;  classbits     the bit map for characters < 256
   uchardptr     points to the pointer for extra data
   options       the options word
   cd            contains pointers to tables etc.
   p             points to row of 32-bit values, terminated by NOTACHAR
   except        character to omit; this is used when adding lists of
                   case-equivalent characters to avoid including the one we
                   already know about
   
    case ESC_W:Returns:        the number of < 256 characters added
    return c <= 127 && (cd->ctypes[c] & ctype_word) != 0;                the pointer to extra data is updated
 */
   
    case ESC_h:static int
    case ESC_H:add_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
    switch(c)  compile_data *cd, const pcre_uint32 *p, unsigned int except)
      {{
      case 0x09:int n8 = 0;
      case 0x20:while (p[0] < NOTACHAR)
      case 0xa0:  {
      case 0x1680:  int n = 0;
      case 0x180e:  if (p[0] != except)
      case 0x2000:    {
      case 0x2001:    while(p[n+1] == p[0] + n + 1) n++;
      case 0x2002:    n8 += add_to_class(classbits, uchardptr, options, cd, p[0], p[n]);
      case 0x2003: 
      case 0x2004: 
      case 0x2005: 
      case 0x2006: 
      case 0x2007: 
      case 0x2008: 
      case 0x2009: 
      case 0x200A: 
      case 0x202f: 
      case 0x205f: 
      case 0x3000: 
      return -next != ESC_h; 
      default: 
      return -next == ESC_h; 
      } 
 
    case ESC_v: 
    case ESC_V: 
    switch(c) 
      { 
      case 0x0a: 
      case 0x0b: 
      case 0x0c: 
      case 0x0d: 
      case 0x85: 
      case 0x2028: 
      case 0x2029: 
      return -next != ESC_v; 
      default: 
      return -next == ESC_v; 
      } 
 
    /* When PCRE_UCP is set, these values get generated for \d etc. Find 
    their substitutions and process them. The result will always be either 
    -ESC_p or -ESC_P. Then fall through to process those values. */ 
 
#ifdef SUPPORT_UCP 
    case ESC_du: 
    case ESC_DU: 
    case ESC_wu: 
    case ESC_WU: 
    case ESC_su: 
    case ESC_SU: 
      { 
      int temperrorcode = 0; 
      ptr = substitutes[-next - ESC_DU]; 
      next = check_escape(&ptr, &temperrorcode, 0, options, FALSE); 
      if (temperrorcode != 0) return FALSE; 
      ptr++;    /* For compatibility */ 
      } 
    /* Fall through */ 
 
    case ESC_p: 
    case ESC_P: 
      { 
      int ptype, pdata, errorcodeptr; 
      BOOL negated; 
 
      ptr--;      /* Make ptr point at the p or P */ 
      ptype = get_ucp(&ptr, &negated, &pdata, &errorcodeptr); 
      if (ptype < 0) return FALSE; 
      ptr++;      /* Point past the final curly ket */ 
 
      /* If the property item is optional, we have to give up. (When generated 
      from \d etc by PCRE_UCP, this test will have been applied much earlier, 
      to the original \d etc. At this point, ptr will point to a zero byte. */ 
 
      if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK || 
        strncmp((char *)ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0) 
          return FALSE; 
 
      /* Do the property check. */ 
 
      return check_char_prop(c, ptype, pdata, (next == -ESC_P) != negated); 
      } 
#endif 
 
    default: 
    return FALSE; 
     }      }
     p += n + 1;
     }
   return n8;
   }
   
   /* In principle, support for Unicode properties should be integrated here as  
   well. It means re-organizing the above code so as to get hold of the property  
   values before switching on the op-code. However, I wonder how many patterns  
   combine ASCII \d etc with Unicode properties? (Note that if PCRE_UCP is set,  
   these op-codes are never generated.) */  
   
   case OP_DIGIT:  
   return next == -ESC_D || next == -ESC_s || next == -ESC_W ||  
          next == -ESC_h || next == -ESC_v || next == -ESC_R;  
   
  case OP_NOT_DIGIT:/*************************************************
  return next == -ESC_d;*    Add characters not in a list to a class     *
 *************************************************/
   
  case OP_WHITESPACE:/* This function is used for adding the complement of a list of horizontal or
  return next == -ESC_S || next == -ESC_d || next == -ESC_w || next == -ESC_R;vertical whitespace to a class. The list must be in order.
   
  case OP_NOT_WHITESPACE:Arguments:
  return next == -ESC_s || next == -ESC_h || next == -ESC_v;  classbits     the bit map for characters < 256
   uchardptr     points to the pointer for extra data
   options       the options word
   cd            contains pointers to tables etc.
   p             points to row of 32-bit values, terminated by NOTACHAR
   
  case OP_HSPACE:Returns:        the number of < 256 characters added
  return next == -ESC_S || next == -ESC_H || next == -ESC_d ||                the pointer to extra data is updated
         next == -ESC_w || next == -ESC_v || next == -ESC_R;*/
   
  case OP_NOT_HSPACE:static int
  return next == -ESC_h;add_not_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr,
  int options, compile_data *cd, const pcre_uint32 *p)
  /* Can't have \S in here because VT matches \S (Perl anomaly) */{
  case OP_ANYNL:BOOL utf = (options & PCRE_UTF8) != 0;
  case OP_VSPACE:int n8 = 0;
  return next == -ESC_V || next == -ESC_d || next == -ESC_w;if (p[0] > 0)
  n8 += add_to_class(classbits, uchardptr, options, cd, 0, p[0] - 1);
  case OP_NOT_VSPACE:while (p[0] < NOTACHAR)
  return next == -ESC_v || next == -ESC_R;  {
  while (p[1] == p[0] + 1) p++;
  case OP_WORDCHAR:  n8 += add_to_class(classbits, uchardptr, options, cd, p[0] + 1,
  return next == -ESC_W || next == -ESC_s || next == -ESC_h ||    (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
         next == -ESC_v || next == -ESC_R;  p++;
 
  case OP_NOT_WORDCHAR: 
  return next == -ESC_w || next == -ESC_d; 
 
  default: 
  return FALSE; 
   }    }
return n8;
/* Control does not reach here */ 
 }  }
   
   
Line 3244  to find out the amount of memory needed, as well as du Line 4328  to find out the amount of memory needed, as well as du
 phase. The value of lengthptr distinguishes the two phases.  phase. The value of lengthptr distinguishes the two phases.
   
 Arguments:  Arguments:
  optionsptr     pointer to the option bits  optionsptr        pointer to the option bits
  codeptr        points to the pointer to the current code point  codeptr           points to the pointer to the current code point
  ptrptr         points to the current pattern pointer  ptrptr            points to the current pattern pointer
  errorcodeptr   points to error code variable  errorcodeptr      points to error code variable
  firstbyteptr   set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)  firstcharptr      place to put the first required character
  reqbyteptr     set to the last literal character required, else < 0  firstcharflagsptr place to put the first character flags, or a negative number
  bcptr          points to current branch chain  reqcharptr        place to put the last required character
  cond_depth     conditional nesting depth  reqcharflagsptr   place to put the last required character flags, or a negative number
  cd             contains pointers to tables etc.  bcptr             points to current branch chain
  lengthptr      NULL during the real compile phase  cond_depth        conditional nesting depth
                 points to length accumulator during pre-compile phase  cd                contains pointers to tables etc.
   lengthptr         NULL during the real compile phase
                     points to length accumulator during pre-compile phase
   
Returns:         TRUE on successReturns:            TRUE on success
                 FALSE, with *errorcodeptr set non-zero on error                    FALSE, with *errorcodeptr set non-zero on error
 */  */
   
 static BOOL  static BOOL
compile_branch(int *optionsptr, uschar **codeptr, const uschar **ptrptr,compile_branch(int *optionsptr, pcre_uchar **codeptr,
  int *errorcodeptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr,  const pcre_uchar **ptrptr, int *errorcodeptr,
  int cond_depth, compile_data *cd, int *lengthptr)  pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
   pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
   branch_chain *bcptr, int cond_depth,
   compile_data *cd, int *lengthptr)
 {  {
 int repeat_type, op_type;  int repeat_type, op_type;
 int repeat_min = 0, repeat_max = 0;      /* To please picky compilers */  int repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
 int bravalue = 0;  int bravalue = 0;
 int greedy_default, greedy_non_default;  int greedy_default, greedy_non_default;
int firstbyte, reqbyte;pcre_uint32 firstchar, reqchar;
int zeroreqbyte, zerofirstbyte;pcre_int32 firstcharflags, reqcharflags;
int req_caseopt, reqvary, tempreqvary;pcre_uint32 zeroreqchar, zerofirstchar;
 pcre_int32 zeroreqcharflags, zerofirstcharflags;
 pcre_int32 req_caseopt, reqvary, tempreqvary;
 int options = *optionsptr;               /* May change dynamically */  int options = *optionsptr;               /* May change dynamically */
 int after_manual_callout = 0;  int after_manual_callout = 0;
 int length_prevgroup = 0;  int length_prevgroup = 0;
register int c;register pcre_uint32 c;
register uschar *code = *codeptr;int escape;
uschar *last_code = code;register pcre_uchar *code = *codeptr;
uschar *orig_code = code;pcre_uchar *last_code = code;
uschar *tempcode;pcre_uchar *orig_code = code;
 pcre_uchar *tempcode;
 BOOL inescq = FALSE;  BOOL inescq = FALSE;
BOOL groupsetfirstbyte = FALSE;BOOL groupsetfirstchar = FALSE;
const uschar *ptr = *ptrptr;const pcre_uchar *ptr = *ptrptr;
const uschar *tempptr;const pcre_uchar *tempptr;
const uschar *nestptr = NULL;const pcre_uchar *nestptr = NULL;
uschar *previous = NULL;pcre_uchar *previous = NULL;
uschar *previous_callout = NULL;pcre_uchar *previous_callout = NULL;
uschar *save_hwm = NULL;pcre_uchar *save_hwm = NULL;
uschar classbits[32];pcre_uint8 classbits[32];
   
 /* We can fish out the UTF-8 setting once and for all into a BOOL, but we  /* We can fish out the UTF-8 setting once and for all into a BOOL, but we
 must not do this for other options (e.g. PCRE_EXTENDED) because they may change  must not do this for other options (e.g. PCRE_EXTENDED) because they may change
 dynamically as we process the pattern. */  dynamically as we process the pattern. */
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
BOOL class_utf8;/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
BOOL utf8 = (options & PCRE_UTF8) != 0;BOOL utf = (options & PCRE_UTF8) != 0;
uschar *class_utf8data;#ifndef COMPILE_PCRE32
uschar *class_utf8data_base;pcre_uchar utf_chars[6];
uschar utf8_char[6];#endif
 #else  #else
BOOL utf8 = FALSE;BOOL utf = FALSE;
 #endif  #endif
   
   /* Helper variables for OP_XCLASS opcode (for characters > 255). We define
   class_uchardata always so that it can be passed to add_to_class() always,
   though it will not be used in non-UTF 8-bit cases. This avoids having to supply
   alternative calls for the different cases. */
   
   pcre_uchar *class_uchardata;
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
   BOOL xclass;
   pcre_uchar *class_uchardata_base;
   #endif
   
 #ifdef PCRE_DEBUG  #ifdef PCRE_DEBUG
 if (lengthptr != NULL) DPRINTF((">> start branch\n"));  if (lengthptr != NULL) DPRINTF((">> start branch\n"));
 #endif  #endif
Line 3315  greedy_non_default = greedy_default ^ 1; Line 4418  greedy_non_default = greedy_default ^ 1;
   
 /* Initialize no first byte, no required byte. REQ_UNSET means "no char  /* Initialize no first byte, no required byte. REQ_UNSET means "no char
 matching encountered yet". It gets changed to REQ_NONE if we hit something that  matching encountered yet". It gets changed to REQ_NONE if we hit something that
matches a non-fixed char first char; reqbyte just remains unset if we nevermatches a non-fixed char first char; reqchar just remains unset if we never
 find one.  find one.
   
 When we hit a repeat whose minimum is zero, we may have to adjust these values  When we hit a repeat whose minimum is zero, we may have to adjust these values
 to take the zero repeat into account. This is implemented by setting them to  to take the zero repeat into account. This is implemented by setting them to
zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individualzerofirstbyte and zeroreqchar when such a repeat is encountered. The individual
 item types that can be repeated set these backoff variables appropriately. */  item types that can be repeated set these backoff variables appropriately. */
   
firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET;firstchar = reqchar = zerofirstchar = zeroreqchar = 0;
 firstcharflags = reqcharflags = zerofirstcharflags = zeroreqcharflags = REQ_UNSET;
   
/* The variable req_caseopt contains either the REQ_CASELESS value or zero,/* The variable req_caseopt contains either the REQ_CASELESS value
according to the current setting of the caseless flag. REQ_CASELESS is a bitor zero, according to the current setting of the caseless flag. The
value > 255. It is added into the firstbyte or reqbyte variables to record theREQ_CASELESS leaves the lower 28 bit empty. It is added into the
case status of the value. This is used only for ASCII characters. */firstchar or reqchar variables to record the case status of the
 value. This is used only for ASCII characters. */
   
req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
   
 /* Switch on next character until the end of the branch */  /* Switch on next character until the end of the branch */
   
Line 3342  for (;; ptr++) Line 4447  for (;; ptr++)
   BOOL is_quantifier;    BOOL is_quantifier;
   BOOL is_recurse;    BOOL is_recurse;
   BOOL reset_bracount;    BOOL reset_bracount;
  int class_charcount;  int class_has_8bitchar;
  int class_lastchar;  int class_one_char;
   int newoptions;    int newoptions;
   int recno;    int recno;
   int refsign;    int refsign;
   int skipbytes;    int skipbytes;
  int subreqbyte;  pcre_uint32 subreqchar, subfirstchar;
  int subfirstbyte;  pcre_int32 subreqcharflags, subfirstcharflags;
   int terminator;    int terminator;
  int mclength;  unsigned int mclength;
  int tempbracount;  unsigned int tempbracount;
  uschar mcbuffer[8];  pcre_uint32 ec;
   pcre_uchar mcbuffer[8];
   
  /* Get next byte in the pattern */  /* Get next character in the pattern */
   
   c = *ptr;    c = *ptr;
   
   /* If we are at the end of a nested substitution, revert to the outer level    /* If we are at the end of a nested substitution, revert to the outer level
   string. Nesting only happens one level deep. */    string. Nesting only happens one level deep. */
   
  if (c == 0 && nestptr != NULL)  if (c == CHAR_NULL && nestptr != NULL)
     {      {
     ptr = nestptr;      ptr = nestptr;
     nestptr = NULL;      nestptr = NULL;
Line 3401  for (;; ptr++) Line 4507  for (;; ptr++)
       }        }
   
     *lengthptr += (int)(code - last_code);      *lengthptr += (int)(code - last_code);
    DPRINTF(("length=%d added %d c=%c\n", *lengthptr, (int)(code - last_code),    DPRINTF(("length=%d added %d c=%c (0x%x)\n", *lengthptr,
      c));      (int)(code - last_code), c, c));
   
     /* If "previous" is set and it is not at the start of the work space, move      /* If "previous" is set and it is not at the start of the work space, move
     it back to there, in order to avoid filling up the work space. Otherwise,      it back to there, in order to avoid filling up the work space. Otherwise,
Line 3412  for (;; ptr++) Line 4518  for (;; ptr++)
       {        {
       if (previous > orig_code)        if (previous > orig_code)
         {          {
        memmove(orig_code, previous, code - previous);        memmove(orig_code, previous, IN_UCHARS(code - previous));
         code -= previous - orig_code;          code -= previous - orig_code;
         previous = orig_code;          previous = orig_code;
         }          }
Line 3437  for (;; ptr++) Line 4543  for (;; ptr++)
   
   /* If in \Q...\E, check for the end; if not, we have a literal */    /* If in \Q...\E, check for the end; if not, we have a literal */
   
  if (inescq && c != 0)  if (inescq && c != CHAR_NULL)
     {      {
     if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)      if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
       {        {
Line 3460  for (;; ptr++) Line 4566  for (;; ptr++)
         }          }
       goto NORMAL_CHAR;        goto NORMAL_CHAR;
       }        }
       /* Control does not reach here. */
     }      }
   
  /* Fill in length of a previous callout, except when the next thing is  /* In extended mode, skip white space and comments. We need a loop in order
  a quantifier. */  to check for more white space and more comments after a comment. */
   
   is_quantifier =  
     c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK ||  
     (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1));  
   
   if (!is_quantifier && previous_callout != NULL &&  
        after_manual_callout-- <= 0)  
     {  
     if (lengthptr == NULL)      /* Don't attempt in pre-compile phase */  
       complete_callout(previous_callout, ptr, cd);  
     previous_callout = NULL;  
     }  
   
   /* In extended mode, skip white space and comments. */  
   
   if ((options & PCRE_EXTENDED) != 0)    if ((options & PCRE_EXTENDED) != 0)
     {      {
    if ((cd->ctypes[c] & ctype_space) != 0) continue;    for (;;)
    if (c == CHAR_NUMBER_SIGN) 
       {        {
         while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr);
         if (c != CHAR_NUMBER_SIGN) break;
       ptr++;        ptr++;
      while (*ptr != 0)      while (*ptr != CHAR_NULL)
         {          {
        if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }        if (IS_NEWLINE(ptr))         /* For non-fixed-length newline cases, */
           {                          /* IS_NEWLINE sets cd->nllen. */
           ptr += cd->nllen;
           break;
           }
         ptr++;          ptr++;
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
        if (utf8) while ((*ptr & 0xc0) == 0x80) ptr++;        if (utf) FORWARDCHAR(ptr);
 #endif  #endif
         }          }
      if (*ptr != 0) continue;      c = *ptr;     /* Either NULL or the char after a newline */
 
      /* Else fall through to handle end of string */ 
      c = 0; 
       }        }
     }      }
   
  /* No auto callout for quantifiers. */  /* See if the next thing is a quantifier. */
   
  if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier)  is_quantifier =
     c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK ||
     (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1));
 
   /* Fill in length of a previous callout, except when the next thing is a
   quantifier or when processing a property substitution string in UCP mode. */
 
   if (!is_quantifier && previous_callout != NULL && nestptr == NULL &&
        after_manual_callout-- <= 0)
     {      {
       if (lengthptr == NULL)      /* Don't attempt in pre-compile phase */
         complete_callout(previous_callout, ptr, cd);
       previous_callout = NULL;
       }
   
     /* Create auto callout, except for quantifiers, or while processing property
     strings that are substituted for \w etc in UCP mode. */
   
     if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier && nestptr == NULL)
       {
     previous_callout = code;      previous_callout = code;
     code = auto_callout(code, ptr, cd);      code = auto_callout(code, ptr, cd);
     }      }
   
     /* Process the next pattern item. */
   
   switch(c)    switch(c)
     {      {
     /* ===================================================================*/      /* ===================================================================*/
    case 0:                        /* The branch terminates at string end */    case CHAR_NULL:                /* The branch terminates at string end */
     case CHAR_VERTICAL_LINE:       /* or | or ) */      case CHAR_VERTICAL_LINE:       /* or | or ) */
     case CHAR_RIGHT_PARENTHESIS:      case CHAR_RIGHT_PARENTHESIS:
    *firstbyteptr = firstbyte;    *firstcharptr = firstchar;
    *reqbyteptr = reqbyte;    *firstcharflagsptr = firstcharflags;
     *reqcharptr = reqchar;
     *reqcharflagsptr = reqcharflags;
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
     if (lengthptr != NULL)      if (lengthptr != NULL)
Line 3539  for (;; ptr++) Line 4656  for (;; ptr++)
     previous = NULL;      previous = NULL;
     if ((options & PCRE_MULTILINE) != 0)      if ((options & PCRE_MULTILINE) != 0)
       {        {
      if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;      if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
       *code++ = OP_CIRCM;        *code++ = OP_CIRCM;
       }        }
     else *code++ = OP_CIRC;      else *code++ = OP_CIRC;
Line 3551  for (;; ptr++) Line 4668  for (;; ptr++)
     break;      break;
   
     /* There can never be a first char if '.' is first, whatever happens about      /* There can never be a first char if '.' is first, whatever happens about
    repeats. The value of reqbyte doesn't change either. */    repeats. The value of reqchar doesn't change either. */
   
     case CHAR_DOT:      case CHAR_DOT:
    if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;    if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
    zerofirstbyte = firstbyte;    zerofirstchar = firstchar;
    zeroreqbyte = reqbyte;    zerofirstcharflags = firstcharflags;
     zeroreqchar = reqchar;
     zeroreqcharflags = reqcharflags;
     previous = code;      previous = code;
     *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;      *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;
     break;      break;
Line 3585  for (;; ptr++) Line 4704  for (;; ptr++)
       }        }
     goto NORMAL_CHAR;      goto NORMAL_CHAR;
   
       /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
       used for "start of word" and "end of word". As these are otherwise illegal
       sequences, we don't break anything by recognizing them. They are replaced
       by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are
       erroneous and are handled by the normal code below. */
   
     case CHAR_LEFT_SQUARE_BRACKET:      case CHAR_LEFT_SQUARE_BRACKET:
       if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0)
         {
         nestptr = ptr + 7;
         ptr = sub_start_of_word - 1;
         continue;
         }
   
       if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
         {
         nestptr = ptr + 7;
         ptr = sub_end_of_word - 1;
         continue;
         }
   
       /* Handle a real character class. */
   
     previous = code;      previous = code;
   
     /* PCRE supports POSIX class stuff inside a class. Perl gives an error if      /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
Line 3611  for (;; ptr++) Line 4752  for (;; ptr++)
         {          {
         if (ptr[1] == CHAR_E)          if (ptr[1] == CHAR_E)
           ptr++;            ptr++;
        else if (strncmp((const char *)ptr+1,        else if (STRNCMP_UC_C8(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
                          STR_Q STR_BACKSLASH STR_E, 3) == 0) 
           ptr += 3;            ptr += 3;
         else          else
           break;            break;
Line 3631  for (;; ptr++) Line 4771  for (;; ptr++)
         (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0)          (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0)
       {        {
       *code++ = negate_class? OP_ALLANY : OP_FAIL;        *code++ = negate_class? OP_ALLANY : OP_FAIL;
      if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;      if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
      zerofirstbyte = firstbyte;      zerofirstchar = firstchar;
       zerofirstcharflags = firstcharflags;
       break;        break;
       }        }
   
Line 3642  for (;; ptr++) Line 4783  for (;; ptr++)
   
     should_flip_negation = FALSE;      should_flip_negation = FALSE;
   
    /* Keep a count of chars with values < 256 so that we can optimize the case    /* For optimization purposes, we track some properties of the class:
    of just a single character (as long as it's < 256). However, For higher    class_has_8bitchar will be non-zero if the class contains at least one <
    valued UTF-8 characters, we don't yet do any optimization. */    256 character; class_one_char will be 1 if the class contains just one
     character. */
   
    class_charcount = 0;    class_has_8bitchar = 0;
    class_lastchar = -1;    class_one_char = 0;
   
     /* Initialize the 32-char bit map to all zeros. We build the map in a      /* Initialize the 32-char bit map to all zeros. We build the map in a
    temporary bit of memory, in case the class contains only 1 character (less    temporary bit of memory, in case the class contains fewer than two
    than 256), because in that case the compiled code doesn't use the bit map.    8-bit characters because in that case the compiled code doesn't use the bit
    */    map. */
   
    memset(classbits, 0, 32 * sizeof(uschar));    memset(classbits, 0, 32 * sizeof(pcre_uint8));
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
    class_utf8 = FALSE;                       /* No chars >= 256 */    xclass = FALSE;
    class_utf8data = code + LINK_SIZE + 2;    /* For UTF-8 items */    class_uchardata = code + LINK_SIZE + 2;   /* For XCLASS items */
    class_utf8data_base = class_utf8data;     /* For resetting in pass 1 */    class_uchardata_base = class_uchardata;   /* Save the start */
 #endif  #endif
   
     /* Process characters until ] is reached. By writing this as a "do" it      /* Process characters until ] is reached. By writing this as a "do" it
     means that an initial ] is taken as a data character. At the start of the      means that an initial ] is taken as a data character. At the start of the
     loop, c contains the first byte of the character. */      loop, c contains the first byte of the character. */
   
    if (c != 0) do    if (c != CHAR_NULL) do
       {        {
      const uschar *oldptr;      const pcre_uchar *oldptr;
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
      if (utf8 && c > 127)      if (utf && HAS_EXTRALEN(c))
         {                           /* Braces are required because the */          {                           /* Braces are required because the */
         GETCHARLEN(c, ptr, ptr);    /* macro generates multiple statements */          GETCHARLEN(c, ptr, ptr);    /* macro generates multiple statements */
         }          }
   #endif
   
      /* In the pre-compile phase, accumulate the length of any UTF-8 extra#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
       /* In the pre-compile phase, accumulate the length of any extra
       data and reset the pointer. This is so that very large classes that        data and reset the pointer. This is so that very large classes that
      contain a zillion UTF-8 characters no longer overwrite the work space      contain a zillion > 255 characters no longer overwrite the work space
      (which is on the stack). */      (which is on the stack). We have to remember that there was XCLASS data,
       however. */
   
      if (lengthptr != NULL)      if (lengthptr != NULL && class_uchardata > class_uchardata_base)
         {          {
        *lengthptr += (int)(class_utf8data - class_utf8data_base);        xclass = TRUE;
        class_utf8data = class_utf8data_base;        *lengthptr += class_uchardata - class_uchardata_base;
         class_uchardata = class_uchardata_base;
         }          }
   
 #endif  #endif
   
       /* Inside \Q...\E everything is literal except \E */        /* Inside \Q...\E everything is literal except \E */
Line 3714  for (;; ptr++) Line 4859  for (;; ptr++)
         {          {
         BOOL local_negate = FALSE;          BOOL local_negate = FALSE;
         int posix_class, taboffset, tabopt;          int posix_class, taboffset, tabopt;
        register const uschar *cbits = cd->cbits;        register const pcre_uint8 *cbits = cd->cbits;
        uschar pbits[32];        pcre_uint8 pbits[32];
   
         if (ptr[1] != CHAR_COLON)          if (ptr[1] != CHAR_COLON)
           {            {
Line 3746  for (;; ptr++) Line 4891  for (;; ptr++)
           posix_class = 0;            posix_class = 0;
   
         /* When PCRE_UCP is set, some of the POSIX classes are converted to          /* When PCRE_UCP is set, some of the POSIX classes are converted to
        different escape sequences that use Unicode properties. */        different escape sequences that use Unicode properties \p or \P. Others
         that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP
         directly. */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
         if ((options & PCRE_UCP) != 0)          if ((options & PCRE_UCP) != 0)
           {            {
             unsigned int ptype = 0;
           int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0);            int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0);
   
             /* The posix_substitutes table specifies which POSIX classes can be
             converted to \p or \P items. */
   
           if (posix_substitutes[pc] != NULL)            if (posix_substitutes[pc] != NULL)
             {              {
             nestptr = tempptr + 1;              nestptr = tempptr + 1;
             ptr = posix_substitutes[pc] - 1;              ptr = posix_substitutes[pc] - 1;
             continue;              continue;
             }              }
   
             /* There are three other classes that generate special property calls
             that are recognized only in an XCLASS. */
   
             else switch(posix_class)
               {
               case PC_GRAPH:
               ptype = PT_PXGRAPH;
               /* Fall through */
               case PC_PRINT:
               if (ptype == 0) ptype = PT_PXPRINT;
               /* Fall through */
               case PC_PUNCT:
               if (ptype == 0) ptype = PT_PXPUNCT;
               *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
               *class_uchardata++ = ptype;
               *class_uchardata++ = 0;
               ptr = tempptr + 1;
               continue;
   
               /* For all other POSIX classes, no special action is taken in UCP
               mode. Fall through to the non_UCP case. */
   
               default:
               break;
               }
           }            }
 #endif  #endif
        /* In the non-UCP case, we build the bit map for the POSIX class in a        /* In the non-UCP case, or when UCP makes no difference, we build the
        chunk of local store because we may be adding and subtracting from it,        bit map for the POSIX class in a chunk of local store because we may be
        and we don't want to subtract bits that may be in the main map already.        adding and subtracting from it, and we don't want to subtract bits that
        At the end we or the result into the bit map that is being built. */        may be in the main map already. At the end we or the result into the
         bit map that is being built. */
   
         posix_class *= 3;          posix_class *= 3;
   
         /* Copy in the first table (always present) */          /* Copy in the first table (always present) */
   
         memcpy(pbits, cbits + posix_class_maps[posix_class],          memcpy(pbits, cbits + posix_class_maps[posix_class],
          32 * sizeof(uschar));          32 * sizeof(pcre_uint8));
   
         /* If there is a second table, add or remove it as required. */          /* If there is a second table, add or remove it as required. */
   
Line 3785  for (;; ptr++) Line 4964  for (;; ptr++)
             for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];              for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];
           }            }
   
        /* Not see if we need to remove any special characters. An option        /* Now see if we need to remove any special characters. An option
         value of 1 removes vertical space and 2 removes underscore. */          value of 1 removes vertical space and 2 removes underscore. */
   
         if (tabopt < 0) tabopt = -tabopt;          if (tabopt < 0) tabopt = -tabopt;
Line 3801  for (;; ptr++) Line 4980  for (;; ptr++)
           for (c = 0; c < 32; c++) classbits[c] |= pbits[c];            for (c = 0; c < 32; c++) classbits[c] |= pbits[c];
   
         ptr = tempptr + 1;          ptr = tempptr + 1;
        class_charcount = 10;  /* Set > 1; assumes more than 1 per class */        /* Every class contains at least one < 256 character. */
         class_has_8bitchar = 1;
         /* Every class contains at least two characters. */
         class_one_char = 2;
         continue;    /* End of POSIX syntax handling */          continue;    /* End of POSIX syntax handling */
         }          }
   
       /* Backslash may introduce a single character, or it may introduce one        /* Backslash may introduce a single character, or it may introduce one
       of the specials, which just set a flag. The sequence \b is a special        of the specials, which just set a flag. The sequence \b is a special
       case. Inside a class (and only there) it is treated as backspace. We        case. Inside a class (and only there) it is treated as backspace. We
      assume that other escapes have more than one character in them, so set      assume that other escapes have more than one character in them, so
      class_charcount bigger than one. Unrecognized escapes fall through and      speculatively set both class_has_8bitchar and class_one_char bigger
      are either treated as literal characters (by default), or are faulted if      than one. Unrecognized escapes fall through and are either treated
       as literal characters (by default), or are faulted if
       PCRE_EXTRA is set. */        PCRE_EXTRA is set. */
   
       if (c == CHAR_BACKSLASH)        if (c == CHAR_BACKSLASH)
         {          {
        c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE);        escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options,
           TRUE);
         if (*errorcodeptr != 0) goto FAILED;          if (*errorcodeptr != 0) goto FAILED;
        if (escape == 0) c = ec;
        if (-c == ESC_b) c = CHAR_BS;    /* \b is backspace in a class */        else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */
        else if (-c == ESC_N)            /* \N is not supported in a class */        else if (escape == ESC_N)          /* \N is not supported in a class */
           {            {
           *errorcodeptr = ERR71;            *errorcodeptr = ERR71;
           goto FAILED;            goto FAILED;
           }            }
        else if (-c == ESC_Q)            /* Handle start of quoted string */        else if (escape == ESC_Q)            /* Handle start of quoted string */
           {            {
           if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)            if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
             {              {
Line 3833  for (;; ptr++) Line 5017  for (;; ptr++)
           else inescq = TRUE;            else inescq = TRUE;
           continue;            continue;
           }            }
        else if (-c == ESC_E) continue;  /* Ignore orphan \E */        else if (escape == ESC_E) continue;  /* Ignore orphan \E */
   
        if (c < 0)        else
           {            {
          register const uschar *cbits = cd->cbits;          register const pcre_uint8 *cbits = cd->cbits;
          class_charcount += 2;     /* Greater than 1 is what matters */          /* Every class contains at least two < 256 characters. */
           class_has_8bitchar++;
           /* Every class contains at least two characters. */
           class_one_char += 2;
   
          switch (-c)          switch (escape)
             {              {
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
             case ESC_du:     /* These are the values given for \d etc */              case ESC_du:     /* These are the values given for \d etc */
Line 3850  for (;; ptr++) Line 5037  for (;; ptr++)
             case ESC_su:     /* of the default ASCII testing. */              case ESC_su:     /* of the default ASCII testing. */
             case ESC_SU:              case ESC_SU:
             nestptr = ptr;              nestptr = ptr;
            ptr = substitutes[-c - ESC_DU] - 1;  /* Just before substitute */            ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
            class_charcount -= 2;                /* Undo! */            class_has_8bitchar--;                /* Undo! */
             continue;              continue;
 #endif  #endif
             case ESC_d:              case ESC_d:
Line 3872  for (;; ptr++) Line 5059  for (;; ptr++)
             for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word];              for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word];
             continue;              continue;
   
            /* Perl 5.004 onwards omits VT from \s, but we must preserve it            /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
            if it was previously set by something earlier in the character            5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
            class. */            previously set by something earlier in the character class.
             Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so
             we could just adjust the appropriate bit. From PCRE 8.34 we no
             longer treat \s and \S specially. */
   
             case ESC_s:              case ESC_s:
            classbits[0] |= cbits[cbit_space];            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space];
            classbits[1] |= cbits[cbit_space+1] & ~0x08; 
            for (c = 2; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; 
             continue;              continue;
   
             case ESC_S:              case ESC_S:
             should_flip_negation = TRUE;              should_flip_negation = TRUE;
             for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space];              for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space];
             classbits[1] |= 0x08;    /* Perl 5.004 onwards omits VT from \s */  
             continue;              continue;
   
               /* The rest apply in both UCP and non-UCP cases. */
   
             case ESC_h:              case ESC_h:
            SETBIT(classbits, 0x09); /* VT */            (void)add_list_to_class(classbits, &class_uchardata, options, cd,
            SETBIT(classbits, 0x20); /* SPACE */              PRIV(hspace_list), NOTACHAR);
            SETBIT(classbits, 0xa0); /* NSBP */ 
#ifdef SUPPORT_UTF8 
            if (utf8) 
              { 
              class_utf8 = TRUE; 
              *class_utf8data++ = XCL_SINGLE; 
              class_utf8data += _pcre_ord2utf8(0x1680, class_utf8data); 
              *class_utf8data++ = XCL_SINGLE; 
              class_utf8data += _pcre_ord2utf8(0x180e, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x2000, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x200A, class_utf8data); 
              *class_utf8data++ = XCL_SINGLE; 
              class_utf8data += _pcre_ord2utf8(0x202f, class_utf8data); 
              *class_utf8data++ = XCL_SINGLE; 
              class_utf8data += _pcre_ord2utf8(0x205f, class_utf8data); 
              *class_utf8data++ = XCL_SINGLE; 
              class_utf8data += _pcre_ord2utf8(0x3000, class_utf8data); 
              } 
#endif 
             continue;              continue;
   
             case ESC_H:              case ESC_H:
            for (c = 0; c < 32; c++)            (void)add_not_list_to_class(classbits, &class_uchardata, options,
              {              cd, PRIV(hspace_list));
              int x = 0xff; 
              switch (c) 
                { 
                case 0x09/8: x ^= 1 << (0x09%8); break; 
                case 0x20/8: x ^= 1 << (0x20%8); break; 
                case 0xa0/8: x ^= 1 << (0xa0%8); break; 
                default: break; 
                } 
              classbits[c] |= x; 
              } 
 
#ifdef SUPPORT_UTF8 
            if (utf8) 
              { 
              class_utf8 = TRUE; 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x167f, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x1681, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x180d, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x180f, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x1fff, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x200B, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x202e, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x2030, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x205e, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x2060, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x2fff, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x3001, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); 
              } 
#endif 
             continue;              continue;
   
             case ESC_v:              case ESC_v:
            SETBIT(classbits, 0x0a); /* LF */            (void)add_list_to_class(classbits, &class_uchardata, options, cd,
            SETBIT(classbits, 0x0b); /* VT */              PRIV(vspace_list), NOTACHAR);
            SETBIT(classbits, 0x0c); /* FF */ 
            SETBIT(classbits, 0x0d); /* CR */ 
            SETBIT(classbits, 0x85); /* NEL */ 
#ifdef SUPPORT_UTF8 
            if (utf8) 
              { 
              class_utf8 = TRUE; 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x2028, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); 
              } 
#endif 
             continue;              continue;
   
             case ESC_V:              case ESC_V:
            for (c = 0; c < 32; c++)            (void)add_not_list_to_class(classbits, &class_uchardata, options,
              {              cd, PRIV(vspace_list));
              int x = 0xff; 
              switch (c) 
                { 
                case 0x0a/8: x ^= 1 << (0x0a%8); 
                             x ^= 1 << (0x0b%8); 
                             x ^= 1 << (0x0c%8); 
                             x ^= 1 << (0x0d%8); 
                             break; 
                case 0x85/8: x ^= 1 << (0x85%8); break; 
                default: break; 
                } 
              classbits[c] |= x; 
              } 
 
#ifdef SUPPORT_UTF8 
            if (utf8) 
              { 
              class_utf8 = TRUE; 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x2027, class_utf8data); 
              *class_utf8data++ = XCL_RANGE; 
              class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data); 
              class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data); 
              } 
#endif 
             continue;              continue;
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
Line 4009  for (;; ptr++) Line 5102  for (;; ptr++)
             case ESC_P:              case ESC_P:
               {                {
               BOOL negated;                BOOL negated;
              int pdata;              unsigned int ptype = 0, pdata = 0;
              int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);              if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
              if (ptype < 0) goto FAILED;                goto FAILED;
              class_utf8 = TRUE;              *class_uchardata++ = ((escape == ESC_p) != negated)?
              *class_utf8data++ = ((-c == ESC_p) != negated)? 
                 XCL_PROP : XCL_NOTPROP;                  XCL_PROP : XCL_NOTPROP;
              *class_utf8data++ = ptype;              *class_uchardata++ = ptype;
              *class_utf8data++ = pdata;              *class_uchardata++ = pdata;
              class_charcount -= 2;   /* Not a < 256 character */              class_has_8bitchar--;                /* Undo! */
               continue;                continue;
               }                }
 #endif  #endif
Line 4031  for (;; ptr++) Line 5123  for (;; ptr++)
               *errorcodeptr = ERR7;                *errorcodeptr = ERR7;
               goto FAILED;                goto FAILED;
               }                }
            class_charcount -= 2;  /* Undo the default count from above */            class_has_8bitchar--;    /* Undo the speculative increase. */
            c = *ptr;              /* Get the final character and fall through */            class_one_char -= 2;     /* Undo the speculative increase. */
             c = *ptr;                /* Get the final character and fall through */
             break;              break;
             }              }
           }            }
   
        /* Fall through if we have a single character (c >= 0). This may be        /* Fall through if the escape just defined a single character (c >= 0).
        greater than 256 in UTF-8 mode. */        This may be greater than 256. */
   
           escape = 0;
   
         }   /* End of backslash handling */          }   /* End of backslash handling */
   
      /* A single character may be followed by '-' to form a range. However,      /* A character may be followed by '-' to form a range. However, Perl does
      Perl does not permit ']' to be the end of the range. A '-' character      not permit ']' to be the end of the range. A '-' character at the end is
      at the end is treated as a literal. Perl ignores orphaned \E sequences      treated as a literal. Perl ignores orphaned \E sequences entirely. The
      entirely. The code for handling \Q and \E is messy. */      code for handling \Q and \E is messy. */
   
       CHECK_RANGE:        CHECK_RANGE:
       while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)        while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
Line 4053  for (;; ptr++) Line 5148  for (;; ptr++)
         inescq = FALSE;          inescq = FALSE;
         ptr += 2;          ptr += 2;
         }          }
   
       oldptr = ptr;        oldptr = ptr;
   
      /* Remember \r or \n */      /* Remember if \r or \n were explicitly used */
   
       if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;        if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
   
Line 4064  for (;; ptr++) Line 5158  for (;; ptr++)
   
       if (!inescq && ptr[1] == CHAR_MINUS)        if (!inescq && ptr[1] == CHAR_MINUS)
         {          {
        int d;        pcre_uint32 d;
         ptr += 2;          ptr += 2;
         while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;          while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;
   
Line 4080  for (;; ptr++) Line 5174  for (;; ptr++)
           break;            break;
           }            }
   
        if (*ptr == 0 || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET))        /* Minus (hyphen) at the end of a class is treated as a literal, so put
         back the pointer and jump to handle the character that preceded it. */
 
         if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET))
           {            {
           ptr = oldptr;            ptr = oldptr;
          goto LONE_SINGLE_CHARACTER;          goto CLASS_SINGLE_CHARACTER;
           }            }
   
#ifdef SUPPORT_UTF8        /* Otherwise, we have a potential range; pick up the next character */
        if (utf8)
 #ifdef SUPPORT_UTF
         if (utf)
           {                           /* Braces are required because the */            {                           /* Braces are required because the */
           GETCHARLEN(d, ptr, ptr);    /* macro generates multiple statements */            GETCHARLEN(d, ptr, ptr);    /* macro generates multiple statements */
           }            }
Line 4095  for (;; ptr++) Line 5194  for (;; ptr++)
 #endif  #endif
         d = *ptr;  /* Not UTF-8 mode */          d = *ptr;  /* Not UTF-8 mode */
   
        /* The second part of a range can be a single-character escape, but        /* The second part of a range can be a single-character escape
        not any of the other escapes. Perl 5.6 treats a hyphen as a literal        sequence, but not any of the other escapes. Perl treats a hyphen as a
        in such circumstances. */        literal in such circumstances. However, in Perl's warning mode, a
         warning is given, so PCRE now faults it as it is almost certainly a
         mistake on the user's part. */
   
        if (!inescq && d == CHAR_BACKSLASH)        if (!inescq)
           {            {
          d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE);          if (d == CHAR_BACKSLASH)
          if (*errorcodeptr != 0) goto FAILED;            {
             int descape;
             descape = check_escape(&ptr, &d, errorcodeptr, cd->bracount, options, TRUE);
             if (*errorcodeptr != 0) goto FAILED;
   
          /* \b is backspace; any other special means the '-' was literal */            /* 0 means a character was put into d; \b is backspace; any other
             special causes an error. */
   
          if (d < 0)            if (descape != 0)
            { 
            if (d == -ESC_b) d = CHAR_BS; else 
               {                {
              ptr = oldptr;              if (descape == ESC_b) d = CHAR_BS; else
              goto LONE_SINGLE_CHARACTER;  /* A few lines below */                {
                 *errorcodeptr = ERR83;
                 goto FAILED;
                 }
               }                }
             }              }
   
             /* A hyphen followed by a POSIX class is treated in the same way. */
   
             else if (d == CHAR_LEFT_SQUARE_BRACKET &&
                      (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
                       ptr[1] == CHAR_EQUALS_SIGN) &&
                      check_posix_syntax(ptr, &tempptr))
               {
               *errorcodeptr = ERR83;
               goto FAILED;
               }
           }            }
   
         /* Check that the two values are in the correct order. Optimize          /* Check that the two values are in the correct order. Optimize
        one-character ranges */        one-character ranges. */
   
         if (d < c)          if (d < c)
           {            {
           *errorcodeptr = ERR8;            *errorcodeptr = ERR8;
           goto FAILED;            goto FAILED;
           }            }
           if (d == c) goto CLASS_SINGLE_CHARACTER;  /* A few lines below */
   
        if (d == c) goto LONE_SINGLE_CHARACTER;  /* A few lines below */        /* We have found a character range, so single character optimizations
         cannot be done anymore. Any value greater than 1 indicates that there
         is more than one character. */
   
        /* Remember \r or \n */        class_one_char = 2;
   
           /* Remember an explicit \r or \n, and add the range to the class. */
   
         if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;          if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
   
        /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless        class_has_8bitchar +=
        matching, we have to use an XCLASS with extra data items. Caseless          add_to_class(classbits, &class_uchardata, options, cd, c, d);
        matching for characters > 127 is available only if UCP support is 
        available. */ 
   
#ifdef SUPPORT_UTF8        continue;   /* Go get the next char in the class */
        if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))        }
          { 
          class_utf8 = TRUE; 
   
          /* With UCP support, we can find the other case equivalents of      /* Handle a single character - we can get here for a normal non-escape
          the relevant characters. There may be several ranges. Optimize how      char, or after \ that introduces a single character or for an apparent
          they fit with the basic range. */      range that isn't. Only the value 1 matters for class_one_char, so don't
       increase it if it is already 2 or more ... just in case there's a class
       with a zillion characters in it. */
   
#ifdef SUPPORT_UCP      CLASS_SINGLE_CHARACTER:
          if ((options & PCRE_CASELESS) != 0)      if (class_one_char < 2) class_one_char++;
            { 
            unsigned int occ, ocd; 
            unsigned int cc = c; 
            unsigned int origd = d; 
            while (get_othercase_range(&cc, origd, &occ, &ocd)) 
              { 
              if (occ >= (unsigned int)c && 
                  ocd <= (unsigned int)d) 
                continue;                          /* Skip embedded ranges */ 
   
              if (occ < (unsigned int)c  &&      /* If class_one_char is 1, we have the first single character in the
                  ocd >= (unsigned int)c - 1)      /* Extend the basic range */      class, and there have been no prior ranges, or XCLASS items generated by
                {                                  /* if there is overlap,   */      escapes. If this is the final character in the class, we can optimize by
                c = occ;                           /* noting that if occ < c */      turning the item into a 1-character OP_CHAR[I] if it's positive, or
                continue;                          /* we can't have ocd > d  */      OP_NOT[I] if it's negative. In the positive case, it can cause firstchar
                }                                  /* because a subrange is  */      to be set. Otherwise, there can be no first char if this item is first,
              if (ocd > (unsigned int)d &&      whatever repeat count may follow. In the case of reqchar, save the
                  occ <= (unsigned int)d + 1)      /* always shorter than    */      previous value for reinstating. */
                {                                  /* the basic range.       */ 
                d = ocd; 
                continue; 
                } 
   
              if (occ == ocd)      if (class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
                {        {
                *class_utf8data++ = XCL_SINGLE;        ptr++;
                }        zeroreqchar = reqchar;
              else        zeroreqcharflags = reqcharflags;
                { 
                *class_utf8data++ = XCL_RANGE; 
                class_utf8data += _pcre_ord2utf8(occ, class_utf8data); 
                } 
              class_utf8data += _pcre_ord2utf8(ocd, class_utf8data); 
              } 
            } 
#endif  /* SUPPORT_UCP */ 
   
          /* Now record the original range, possibly modified for UCP caseless        if (negate_class)
          overlapping ranges. */          {
 #ifdef SUPPORT_UCP
           int d;
 #endif
           if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
           zerofirstchar = firstchar;
           zerofirstcharflags = firstcharflags;
   
          *class_utf8data++ = XCL_RANGE;          /* For caseless UTF-8 mode when UCP support is available, check
          class_utf8data += _pcre_ord2utf8(c, class_utf8data);          whether this character has more than one other case. If so, generate
          class_utf8data += _pcre_ord2utf8(d, class_utf8data);          a special OP_NOTPROP item instead of OP_NOTI. */
   
           /* With UCP support, we are done. Without UCP support, there is no  
           caseless matching for UTF-8 characters > 127; we can use the bit map  
           for the smaller ones. */  
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
          continue;    /* With next character in the class */          if (utf && (options & PCRE_CASELESS) != 0 &&
#else              (d = UCD_CASESET(c)) != 0)
          if ((options & PCRE_CASELESS) == 0 || c > 127) continue;            {
             *code++ = OP_NOTPROP;
             *code++ = PT_CLIST;
             *code++ = d;
             }
           else
 #endif
           /* Char has only one other case, or UCP not available */
   
           /* Adjust upper limit and fall through to set up the map */  
   
           d = 127;  
   
 #endif  /* SUPPORT_UCP */  
           }  
 #endif  /* SUPPORT_UTF8 */  
   
         /* We use the bit map for all cases when not in UTF-8 mode; else  
         ranges that lie entirely within 0-127 when there is UCP support; else  
         for partial ranges without UCP support. */  
   
         class_charcount += d - c + 1;  
         class_lastchar = d;  
   
         /* We can save a bit of time by skipping this in the pre-compile. */  
   
         if (lengthptr == NULL) for (; c <= d; c++)  
           {  
           classbits[c/8] |= (1 << (c&7));  
           if ((options & PCRE_CASELESS) != 0)  
             {              {
            int uc = cd->fcc[c];           /* flip case */            *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;
            classbits[uc/8] |= (1 << (uc&7));#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
             if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
               code += PRIV(ord2utf)(c, code);
             else
 #endif
               *code++ = c;
             }              }
           }  
   
        continue;   /* Go get the next char in the class */          /* We are finished with this character class */
        } 
   
      /* Handle a lone single character - we can get here for a normal          goto END_CLASS;
      non-escape char, or after \ that introduces a single character or for an          }
      apparent range that isn't. */ 
   
      LONE_SINGLE_CHARACTER:        /* For a single, positive character, get the value into mcbuffer, and
         then we can handle this with the normal one-character code. */
   
      /* Handle a character that cannot go in the bit map */#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
        if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
#ifdef SUPPORT_UTF8          mclength = PRIV(ord2utf)(c, mcbuffer);
      if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127)))        else
        {#endif
        class_utf8 = TRUE; 
        *class_utf8data++ = XCL_SINGLE; 
        class_utf8data += _pcre_ord2utf8(c, class_utf8data); 
 
#ifdef SUPPORT_UCP 
        if ((options & PCRE_CASELESS) != 0) 
           {            {
          unsigned int othercase;          mcbuffer[0] = c;
          if ((othercase = UCD_OTHERCASE(c)) != c)          mclength = 1;
            { 
            *class_utf8data++ = XCL_SINGLE; 
            class_utf8data += _pcre_ord2utf8(othercase, class_utf8data); 
            } 
           }            }
#endif  /* SUPPORT_UCP */        goto ONE_CHAR;
         }       /* End of 1-char optimization */
   
        }      /* There is more than one character in the class, or an XCLASS item
      else      has been generated. Add this character to the class. */
#endif  /* SUPPORT_UTF8 */ 
   
      /* Handle a single-byte character */      class_has_8bitchar +=
        {        add_to_class(classbits, &class_uchardata, options, cd, c, c);
        classbits[c/8] |= (1 << (c&7)); 
        if ((options & PCRE_CASELESS) != 0) 
          { 
          c = cd->fcc[c];   /* flip case */ 
          classbits[c/8] |= (1 << (c&7)); 
          } 
        class_charcount++; 
        class_lastchar = c; 
        } 
       }        }
   
     /* Loop until ']' reached. This "while" is the end of the "do" far above.      /* Loop until ']' reached. This "while" is the end of the "do" far above.
     If we are at the end of an internal nested string, revert to the outer      If we are at the end of an internal nested string, revert to the outer
     string. */      string. */
   
    while (((c = *(++ptr)) != 0 ||    while (((c = *(++ptr)) != CHAR_NULL ||
            (nestptr != NULL &&             (nestptr != NULL &&
             (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != 0)) &&             (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != CHAR_NULL)) &&
            (c != CHAR_RIGHT_SQUARE_BRACKET || inescq));             (c != CHAR_RIGHT_SQUARE_BRACKET || inescq));
   
     /* Check for missing terminating ']' */      /* Check for missing terminating ']' */
   
    if (c == 0)    if (c == CHAR_NULL)
       {        {
       *errorcodeptr = ERR6;        *errorcodeptr = ERR6;
       goto FAILED;        goto FAILED;
       }        }
   
    /* If class_charcount is 1, we saw precisely one character whose value is    /* We will need an XCLASS if data has been placed in class_uchardata. In
    less than 256. As long as there were no characters >= 128 and there was no    the second phase this is a sufficient test. However, in the pre-compile
    use of \p or \P, in other words, no use of any XCLASS features, we can    phase, class_uchardata gets emptied to prevent workspace overflow, so it
    optimize.    only if the very last character in the class needs XCLASS will it contain
     anything at this point. For this reason, xclass gets set TRUE above when
     uchar_classdata is emptied, and that's why this code is the way it is here
     instead of just doing a test on class_uchardata below. */
   
    In UTF-8 mode, we can optimize the negative case only if there were no#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
    characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR    if (class_uchardata > class_uchardata_base) xclass = TRUE;
    operate on single-bytes characters only. This is an historical hangover. 
    Maybe one day we can tidy these opcodes to handle multi-byte characters. 
 
    The optimization throws away the bit map. We turn the item into a 
    1-character OP_CHAR[I] if it's positive, or OP_NOT[I] if it's negative. 
    Note that OP_NOT[I] does not support multibyte characters. In the positive 
    case, it can cause firstbyte to be set. Otherwise, there can be no first 
    char if this item is first, whatever repeat count may follow. In the case 
    of reqbyte, save the previous value for reinstating. */ 
 
#ifdef SUPPORT_UTF8 
    if (class_charcount == 1 && !class_utf8 && 
      (!utf8 || !negate_class || class_lastchar < 128)) 
#else 
    if (class_charcount == 1) 
 #endif  #endif
       {  
       zeroreqbyte = reqbyte;  
   
      /* The OP_NOT[I] opcodes work on one-byte characters only. */    /* If this is the first thing in the branch, there can be no first char
     setting, whatever the repeat count. Any reqchar setting must remain
     unchanged after any kind of repeat. */
   
      if (negate_class)    if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
        {    zerofirstchar = firstchar;
        if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;    zerofirstcharflags = firstcharflags;
        zerofirstbyte = firstbyte;    zeroreqchar = reqchar;
        *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;    zeroreqcharflags = reqcharflags;
        *code++ = class_lastchar; 
        break; 
        } 
   
       /* For a single, positive character, get the value into mcbuffer, and  
       then we can handle this with the normal one-character code. */  
   
 #ifdef SUPPORT_UTF8  
       if (utf8 && class_lastchar > 127)  
         mclength = _pcre_ord2utf8(class_lastchar, mcbuffer);  
       else  
 #endif  
         {  
         mcbuffer[0] = class_lastchar;  
         mclength = 1;  
         }  
       goto ONE_CHAR;  
       }       /* End of 1-char optimization */  
   
     /* The general case - not the one-char optimization. If this is the first  
     thing in the branch, there can be no first char setting, whatever the  
     repeat count. Any reqbyte setting must remain unchanged after any kind of  
     repeat. */  
   
     if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;  
     zerofirstbyte = firstbyte;  
     zeroreqbyte = reqbyte;  
   
     /* If there are characters with values > 255, we have to compile an      /* If there are characters with values > 255, we have to compile an
     extended class, with its own opcode, unless there was a negated special      extended class, with its own opcode, unless there was a negated special
     such as \S in the class, and PCRE_UCP is not set, because in that case all      such as \S in the class, and PCRE_UCP is not set, because in that case all
Line 4360  for (;; ptr++) Line 5392  for (;; ptr++)
     be listed) there are no characters < 256, we can omit the bitmap in the      be listed) there are no characters < 256, we can omit the bitmap in the
     actual compiled code. */      actual compiled code. */
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
    if (class_utf8 && (!should_flip_negation || (options & PCRE_UCP) != 0))    if (xclass && (!should_flip_negation || (options & PCRE_UCP) != 0))
 #elif !defined COMPILE_PCRE8
     if (xclass && !should_flip_negation)
 #endif
 #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
       {        {
      *class_utf8data++ = XCL_END;    /* Marks the end of extra data */      *class_uchardata++ = XCL_END;    /* Marks the end of extra data */
       *code++ = OP_XCLASS;        *code++ = OP_XCLASS;
       code += LINK_SIZE;        code += LINK_SIZE;
      *code = negate_class? XCL_NOT : 0;      *code = negate_class? XCL_NOT:0;
   
       /* If the map is required, move up the extra data to make room for it;        /* If the map is required, move up the extra data to make room for it;
       otherwise just move the code pointer to the end of the extra data. */        otherwise just move the code pointer to the end of the extra data. */
   
      if (class_charcount > 0)      if (class_has_8bitchar > 0)
         {          {
         *code++ |= XCL_MAP;          *code++ |= XCL_MAP;
        memmove(code + 32, code, class_utf8data - code);        memmove(code + (32 / sizeof(pcre_uchar)), code,
           IN_UCHARS(class_uchardata - code));
         memcpy(code, classbits, 32);          memcpy(code, classbits, 32);
        code = class_utf8data + 32;        code = class_uchardata + (32 / sizeof(pcre_uchar));
         }          }
      else code = class_utf8data;      else code = class_uchardata;
   
       /* Now fill in the complete length of the item */        /* Now fill in the complete length of the item */
   
Line 4394  for (;; ptr++) Line 5431  for (;; ptr++)
     negating it if necessary. */      negating it if necessary. */
   
     *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;      *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;
    if (negate_class)    if (lengthptr == NULL)    /* Save time in the pre-compile phase */
       {        {
      if (lengthptr == NULL)    /* Save time in the pre-compile phase */      if (negate_class)
        for (c = 0; c < 32; c++) code[c] = ~classbits[c];        for (c = 0; c < 32; c++) classbits[c] = ~classbits[c];
      } 
    else 
      { 
       memcpy(code, classbits, 32);        memcpy(code, classbits, 32);
       }        }
    code += 32;    code += 32 / sizeof(pcre_uchar);
 
     END_CLASS:
     break;      break;
   
   
Line 4440  for (;; ptr++) Line 5476  for (;; ptr++)
   
     if (repeat_min == 0)      if (repeat_min == 0)
       {        {
      firstbyte = zerofirstbyte;    /* Adjust for zero repeat */      firstchar = zerofirstchar;    /* Adjust for zero repeat */
      reqbyte = zeroreqbyte;        /* Ditto */      firstcharflags = zerofirstcharflags;
       reqchar = zeroreqchar;        /* Ditto */
       reqcharflags = zeroreqcharflags;
       }        }
   
     /* Remember whether this is a variable length repeat */      /* Remember whether this is a variable length repeat */
Line 4456  for (;; ptr++) Line 5494  for (;; ptr++)
   
     tempcode = previous;      tempcode = previous;
   
       /* Before checking for a possessive quantifier, we must skip over
       whitespace and comments in extended mode because Perl allows white space at
       this point. */
   
       if ((options & PCRE_EXTENDED) != 0)
         {
         const pcre_uchar *p = ptr + 1;
         for (;;)
           {
           while (MAX_255(*p) && (cd->ctypes[*p] & ctype_space) != 0) p++;
           if (*p != CHAR_NUMBER_SIGN) break;
           p++;
           while (*p != CHAR_NULL)
             {
             if (IS_NEWLINE(p))         /* For non-fixed-length newline cases, */
               {                        /* IS_NEWLINE sets cd->nllen. */
               p += cd->nllen;
               break;
               }
             p++;
   #ifdef SUPPORT_UTF
             if (utf) FORWARDCHAR(p);
   #endif
             }           /* Loop for comment characters */
           }             /* Loop for multiple comments */
         ptr = p - 1;    /* Character before the next significant one. */
         }
   
     /* If the next character is '+', we have a possessive quantifier. This      /* If the next character is '+', we have a possessive quantifier. This
     implies greediness, whatever the setting of the PCRE_UNGREEDY option.      implies greediness, whatever the setting of the PCRE_UNGREEDY option.
     If the next character is '?' this is a minimizing repeat, by default,      If the next character is '?' this is a minimizing repeat, by default,
Line 4483  for (;; ptr++) Line 5549  for (;; ptr++)
   
     if (*previous == OP_RECURSE)      if (*previous == OP_RECURSE)
       {        {
      memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE);      memmove(previous + 1 + LINK_SIZE, previous, IN_UCHARS(1 + LINK_SIZE));
       *previous = OP_ONCE;        *previous = OP_ONCE;
       PUT(previous, 1, 2 + 2*LINK_SIZE);        PUT(previous, 1, 2 + 2*LINK_SIZE);
       previous[2 + 2*LINK_SIZE] = OP_KET;        previous[2 + 2*LINK_SIZE] = OP_KET;
Line 4504  for (;; ptr++) Line 5570  for (;; ptr++)
   
     /* Now handle repetition for the different types of item. */      /* Now handle repetition for the different types of item. */
   
    /* If previous was a character match, abolish the item and generate a    /* If previous was a character or negated character match, abolish the item
    repeat item instead. If a char item has a minumum of more than one, ensure    and generate a repeat item instead. If a char item has a minimum of more
    that it is set in reqbyte - it might not be if a sequence such as x{3} is    than one, ensure that it is set in reqchar - it might not be if a sequence
    the first thing in a branch because the x will have gone into firstbyte    such as x{3} is the first thing in a branch because the x will have gone
    instead.  */    into firstchar instead.  */
   
    if (*previous == OP_CHAR || *previous == OP_CHARI)    if (*previous == OP_CHAR || *previous == OP_CHARI
         || *previous == OP_NOT || *previous == OP_NOTI)
       {        {
      op_type = (*previous == OP_CHAR)? 0 : OP_STARI - OP_STAR;      switch (*previous)
         {
         default: /* Make compiler happy. */
         case OP_CHAR:  op_type = OP_STAR - OP_STAR; break;
         case OP_CHARI: op_type = OP_STARI - OP_STAR; break;
         case OP_NOT:   op_type = OP_NOTSTAR - OP_STAR; break;
         case OP_NOTI:  op_type = OP_NOTSTARI - OP_STAR; break;
         }
   
      /* Deal with UTF-8 characters that take up more than one byte. It's      /* Deal with UTF characters that take up more than one character. It's
       easier to write this out separately than try to macrify it. Use c to        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      hold the length of the character in bytes, plus UTF_LENGTH to flag that
      length rather than a small character. */      it's a length rather than a small character. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
      if (utf8 && (code[-1] & 0x80) != 0)      if (utf && NOT_FIRSTCHAR(code[-1]))
         {          {
        uschar *lastchar = code - 1;        pcre_uchar *lastchar = code - 1;
        while((*lastchar & 0xc0) == 0x80) lastchar--;        BACKCHAR(lastchar);
         c = (int)(code - lastchar);     /* Length of UTF-8 character */          c = (int)(code - lastchar);     /* Length of UTF-8 character */
        memcpy(utf8_char, lastchar, c); /* Save the char */        memcpy(utf_chars, lastchar, IN_UCHARS(c)); /* Save the char */
        c |= 0x80;                      /* Flag c as a length */        c |= UTF_LENGTH;                /* Flag c as a length */
         }          }
       else        else
#endif#endif /* SUPPORT_UTF */
   
      /* Handle the case of a single byte - either with no UTF8 support, or      /* Handle the case of a single charater - either with no UTF support, or
      with UTF-8 disabled, or for a UTF-8 character < 128. */      with UTF disabled, or for a single character UTF character. */
 
         {          {
         c = code[-1];          c = code[-1];
        if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt;        if (*previous <= OP_CHARI && repeat_min > 1)
           {
           reqchar = c;
           reqcharflags = req_caseopt | cd->req_varyopt;
           }
         }          }
   
       /* If the repetition is unlimited, it pays to see if the next thing on  
       the line is something that cannot possibly match this character. If so,  
       automatically possessifying this item gains some performance in the case  
       where the match fails. */  
   
       if (!possessive_quantifier &&  
           repeat_max < 0 &&  
           check_auto_possessive(previous, utf8, ptr + 1, options, cd))  
         {  
         repeat_type = 0;    /* Force greedy */  
         possessive_quantifier = TRUE;  
         }  
   
       goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */        goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
       }        }
   
     /* 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  
     are currently used only for single-byte chars. */  
   
     else if (*previous == OP_NOT || *previous == OP_NOTI)  
       {  
       op_type = ((*previous == OP_NOT)? OP_NOTSTAR : OP_NOTSTARI) - OP_STAR;  
       c = previous[1];  
       if (!possessive_quantifier &&  
           repeat_max < 0 &&  
           check_auto_possessive(previous, utf8, ptr + 1, options, cd))  
         {  
         repeat_type = 0;    /* Force greedy */  
         possessive_quantifier = TRUE;  
         }  
       goto OUTPUT_SINGLE_REPEAT;  
       }  
   
     /* If previous was a character type match (\d or similar), abolish it and      /* If previous was a character type match (\d or similar), abolish it and
     create a suitable repeat item. The code is shared with single-character      create a suitable repeat item. The code is shared with single-character
     repeats by setting op_type to add a suitable offset into repeat_type. Note      repeats by setting op_type to add a suitable offset into repeat_type. Note
Line 4584  for (;; ptr++) Line 5628  for (;; ptr++)
   
     else if (*previous < OP_EODN)      else if (*previous < OP_EODN)
       {        {
      uschar *oldcode;      pcre_uchar *oldcode;
       int prop_type, prop_value;        int prop_type, prop_value;
       op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */        op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
       c = *previous;        c = *previous;
   
       if (!possessive_quantifier &&  
           repeat_max < 0 &&  
           check_auto_possessive(previous, utf8, ptr + 1, options, cd))  
         {  
         repeat_type = 0;    /* Force greedy */  
         possessive_quantifier = TRUE;  
         }  
   
       OUTPUT_SINGLE_REPEAT:        OUTPUT_SINGLE_REPEAT:
       if (*previous == OP_PROP || *previous == OP_NOTPROP)        if (*previous == OP_PROP || *previous == OP_NOTPROP)
         {          {
Line 4613  for (;; ptr++) Line 5649  for (;; ptr++)
   
       if (repeat_max == 0) goto END_REPEAT;        if (repeat_max == 0) goto END_REPEAT;
   
       /*--------------------------------------------------------------------*/  
       /* This code is obsolete from release 8.00; the restriction was finally  
       removed: */  
   
       /* All real repeats make it impossible to handle partial matching (maybe  
       one day we will be able to remove this restriction). */  
   
       /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */  
       /*--------------------------------------------------------------------*/  
   
       /* Combine the op_type with the repeat_type */        /* Combine the op_type with the repeat_type */
   
       repeat_type += op_type;        repeat_type += op_type;
Line 4671  for (;; ptr++) Line 5697  for (;; ptr++)
         we have to insert the character for the previous code. For a repeated          we have to insert the character for the previous code. For a repeated
         Unicode property match, there are two extra bytes that define the          Unicode property match, there are two extra bytes that define the
         required property. In UTF-8 mode, long characters have their length in          required property. In UTF-8 mode, long characters have their length in
        c, with the 0x80 bit as a flag. */        c, with the UTF_LENGTH bit as a flag. */
   
         if (repeat_max < 0)          if (repeat_max < 0)
           {            {
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
          if (utf8 && c >= 128)          if (utf && (c & UTF_LENGTH) != 0)
             {              {
            memcpy(code, utf8_char, c & 7);            memcpy(code, utf_chars, IN_UCHARS(c & 7));
             code += c & 7;              code += c & 7;
             }              }
           else            else
Line 4700  for (;; ptr++) Line 5726  for (;; ptr++)
   
         else if (repeat_max != repeat_min)          else if (repeat_max != repeat_min)
           {            {
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
          if (utf8 && c >= 128)          if (utf && (c & UTF_LENGTH) != 0)
             {              {
            memcpy(code, utf8_char, c & 7);            memcpy(code, utf_chars, IN_UCHARS(c & 7));
             code += c & 7;              code += c & 7;
             }              }
           else            else
Line 4730  for (;; ptr++) Line 5756  for (;; ptr++)
   
       /* The character or character type itself comes last in all cases. */        /* The character or character type itself comes last in all cases. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
      if (utf8 && c >= 128)      if (utf && (c & UTF_LENGTH) != 0)
         {          {
        memcpy(code, utf8_char, c & 7);        memcpy(code, utf_chars, IN_UCHARS(c & 7));
         code += c & 7;          code += c & 7;
         }          }
       else        else
Line 4755  for (;; ptr++) Line 5781  for (;; ptr++)
     /* If previous was a character class or a back reference, we put the repeat      /* If previous was a character class or a back reference, we put the repeat
     stuff after it, but just skip the item if the repeat was {0,0}. */      stuff after it, but just skip the item if the repeat was {0,0}. */
   
    else if (*previous == OP_CLASS ||    else if (*previous == OP_CLASS || *previous == OP_NCLASS ||
             *previous == OP_NCLASS ||#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
#ifdef SUPPORT_UTF8 
              *previous == OP_XCLASS ||               *previous == OP_XCLASS ||
 #endif  #endif
             *previous == OP_REF ||             *previous == OP_REF   || *previous == OP_REFI ||
             *previous == OP_REFI)             *previous == OP_DNREF || *previous == OP_DNREFI)
       {        {
       if (repeat_max == 0)        if (repeat_max == 0)
         {          {
Line 4769  for (;; ptr++) Line 5794  for (;; ptr++)
         goto END_REPEAT;          goto END_REPEAT;
         }          }
   
       /*--------------------------------------------------------------------*/  
       /* This code is obsolete from release 8.00; the restriction was finally  
       removed: */  
   
       /* All real repeats make it impossible to handle partial matching (maybe  
       one day we will be able to remove this restriction). */  
   
       /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */  
       /*--------------------------------------------------------------------*/  
   
       if (repeat_min == 0 && repeat_max == -1)        if (repeat_min == 0 && repeat_max == -1)
         *code++ = OP_CRSTAR + repeat_type;          *code++ = OP_CRSTAR + repeat_type;
       else if (repeat_min == 1 && repeat_max == -1)        else if (repeat_min == 1 && repeat_max == -1)
Line 4799  for (;; ptr++) Line 5814  for (;; ptr++)
     opcodes such as BRA and CBRA, as this is the place where they get converted      opcodes such as BRA and CBRA, as this is the place where they get converted
     into the more special varieties such as BRAPOS and SBRA. A test for >=      into the more special varieties such as BRAPOS and SBRA. A test for >=
     OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK,      OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK,
    ASSERTBACK_NOT, ONCE, BRA, CBRA, and COND. Originally, PCRE did not allow    ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND.
    repetition of assertions, but now it does, for Perl compatibility. */    Originally, PCRE did not allow repetition of assertions, but now it does,
     for Perl compatibility. */
   
     else if (*previous >= OP_ASSERT && *previous <= OP_COND)      else if (*previous >= OP_ASSERT && *previous <= OP_COND)
       {        {
       register int i;        register int i;
       int len = (int)(code - previous);        int len = (int)(code - previous);
      uschar *bralink = NULL;      pcre_uchar *bralink = NULL;
      uschar *brazeroptr = NULL;      pcre_uchar *brazeroptr = NULL;
   
       /* Repeating a DEFINE group is pointless, but Perl allows the syntax, so        /* Repeating a DEFINE group is pointless, but Perl allows the syntax, so
       we just ignore the repeat. */        we just ignore the repeat. */
Line 4818  for (;; ptr++) Line 5834  for (;; ptr++)
       /* There is no sense in actually repeating assertions. The only potential        /* There is no sense in actually repeating assertions. The only potential
       use of repetition is in cases when the assertion is optional. Therefore,        use of repetition is in cases when the assertion is optional. Therefore,
       if the minimum is greater than zero, just ignore the repeat. If the        if the minimum is greater than zero, just ignore the repeat. If the
      maximum is not not zero or one, set it to 1. */      maximum is not zero or one, set it to 1. */
   
       if (*previous < OP_ONCE)    /* Assertion */        if (*previous < OP_ONCE)    /* Assertion */
         {          {
Line 4860  for (;; ptr++) Line 5876  for (;; ptr++)
         if (repeat_max <= 1)    /* Covers 0, 1, and unlimited */          if (repeat_max <= 1)    /* Covers 0, 1, and unlimited */
           {            {
           *code = OP_END;            *code = OP_END;
          adjust_recurse(previous, 1, utf8, cd, save_hwm);          adjust_recurse(previous, 1, utf, cd, save_hwm);
          memmove(previous+1, previous, len);          memmove(previous + 1, previous, IN_UCHARS(len));
           code++;            code++;
           if (repeat_max == 0)            if (repeat_max == 0)
             {              {
Line 4884  for (;; ptr++) Line 5900  for (;; ptr++)
           {            {
           int offset;            int offset;
           *code = OP_END;            *code = OP_END;
          adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd, save_hwm);          adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm);
          memmove(previous + 2 + LINK_SIZE, previous, len);          memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
           code += 2 + LINK_SIZE;            code += 2 + LINK_SIZE;
           *previous++ = OP_BRAZERO + repeat_type;            *previous++ = OP_BRAZERO + repeat_type;
           *previous++ = OP_BRA;            *previous++ = OP_BRA;
Line 4938  for (;; ptr++) Line 5954  for (;; ptr++)
   
           else            else
             {              {
            if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte;            if (groupsetfirstchar && reqcharflags < 0)
               {
               reqchar = firstchar;
               reqcharflags = firstcharflags;
               }
   
             for (i = 1; i < repeat_min; i++)              for (i = 1; i < repeat_min; i++)
               {                {
              uschar *hc;              pcre_uchar *hc;
              uschar *this_hwm = cd->hwm;              pcre_uchar *this_hwm = cd->hwm;
              memcpy(code, previous, len);              memcpy(code, previous, IN_UCHARS(len));
   
               while (cd->hwm > cd->start_workspace + cd->workspace_size -                while (cd->hwm > cd->start_workspace + cd->workspace_size -
                      WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))                       WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
Line 4953  for (;; ptr++) Line 5973  for (;; ptr++)
                 int this_offset = this_hwm - cd->start_workspace;                  int this_offset = this_hwm - cd->start_workspace;
                 *errorcodeptr = expand_workspace(cd);                  *errorcodeptr = expand_workspace(cd);
                 if (*errorcodeptr != 0) goto FAILED;                  if (*errorcodeptr != 0) goto FAILED;
                save_hwm = (uschar *)cd->start_workspace + save_offset;                save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
                this_hwm = (uschar *)cd->start_workspace + this_offset;                this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
                 }                  }
   
               for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)                for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
Line 5006  for (;; ptr++) Line 6026  for (;; ptr++)
   
         else for (i = repeat_max - 1; i >= 0; i--)          else for (i = repeat_max - 1; i >= 0; i--)
           {            {
          uschar *hc;          pcre_uchar *hc;
          uschar *this_hwm = cd->hwm;          pcre_uchar *this_hwm = cd->hwm;
   
           *code++ = OP_BRAZERO + repeat_type;            *code++ = OP_BRAZERO + repeat_type;
   
Line 5023  for (;; ptr++) Line 6043  for (;; ptr++)
             PUTINC(code, 0, offset);              PUTINC(code, 0, offset);
             }              }
   
          memcpy(code, previous, len);          memcpy(code, previous, IN_UCHARS(len));
   
           /* Ensure there is enough workspace for forward references before            /* Ensure there is enough workspace for forward references before
           copying them. */            copying them. */
Line 5035  for (;; ptr++) Line 6055  for (;; ptr++)
             int this_offset = this_hwm - cd->start_workspace;              int this_offset = this_hwm - cd->start_workspace;
             *errorcodeptr = expand_workspace(cd);              *errorcodeptr = expand_workspace(cd);
             if (*errorcodeptr != 0) goto FAILED;              if (*errorcodeptr != 0) goto FAILED;
            save_hwm = (uschar *)cd->start_workspace + save_offset;            save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
            this_hwm = (uschar *)cd->start_workspace + this_offset;            this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
             }              }
   
           for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)            for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
Line 5055  for (;; ptr++) Line 6075  for (;; ptr++)
           {            {
           int oldlinkoffset;            int oldlinkoffset;
           int offset = (int)(code - bralink + 1);            int offset = (int)(code - bralink + 1);
          uschar *bra = code - offset;          pcre_uchar *bra = code - offset;
           oldlinkoffset = GET(bra, 1);            oldlinkoffset = GET(bra, 1);
           bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;            bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
           *code++ = OP_KET;            *code++ = OP_KET;
Line 5091  for (;; ptr++) Line 6111  for (;; ptr++)
   
       else        else
         {          {
        uschar *ketcode = code - 1 - LINK_SIZE;        pcre_uchar *ketcode = code - 1 - LINK_SIZE;
        uschar *bracode = ketcode - GET(ketcode, 1);        pcre_uchar *bracode = ketcode - GET(ketcode, 1);
   
         /* Convert possessive ONCE brackets to non-capturing */          /* Convert possessive ONCE brackets to non-capturing */
   
Line 5114  for (;; ptr++) Line 6134  for (;; ptr++)
   
           if (lengthptr == NULL)            if (lengthptr == NULL)
             {              {
            uschar *scode = bracode;            pcre_uchar *scode = bracode;
             do              do
               {                {
              if (could_be_empty_branch(scode, ketcode, utf8, cd))              if (could_be_empty_branch(scode, ketcode, utf, cd, NULL))
                 {                  {
                 *bracode += OP_SBRA - OP_BRA;                  *bracode += OP_SBRA - OP_BRA;
                 break;                  break;
Line 5140  for (;; ptr++) Line 6160  for (;; ptr++)
               {                {
               int nlen = (int)(code - bracode);                int nlen = (int)(code - bracode);
               *code = OP_END;                *code = OP_END;
              adjust_recurse(bracode, 1 + LINK_SIZE, utf8, cd, save_hwm);              adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm);
              memmove(bracode + 1+LINK_SIZE, bracode, nlen);              memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
               code += 1 + LINK_SIZE;                code += 1 + LINK_SIZE;
               nlen += 1 + LINK_SIZE;                nlen += 1 + LINK_SIZE;
               *bracode = OP_BRAPOS;                *bracode = OP_BRAPOS;
Line 5187  for (;; ptr++) Line 6207  for (;; ptr++)
       goto FAILED;        goto FAILED;
       }        }
   
    /* If the character following a repeat is '+', or if certain optimization    /* If the character following a repeat is '+', possessive_quantifier is
    tests above succeeded, possessive_quantifier is TRUE. For some opcodes,    TRUE. For some opcodes, there are special alternative opcodes for this
    there are special alternative opcodes for this case. For anything else, we    case. For anything else, we wrap the entire repeated item inside OP_ONCE
    wrap the entire repeated item inside OP_ONCE brackets. Logically, the '+'    brackets. Logically, the '+' notation is just syntactic sugar, taken from
    notation is just syntactic sugar, taken from Sun's Java package, but the    Sun's Java package, but the special opcodes can optimize it.
    special opcodes can optimize it. 
   
     Some (but not all) possessively repeated subpatterns have already been      Some (but not all) possessively repeated subpatterns have already been
     completely handled in the code just above. For them, possessive_quantifier      completely handled in the code just above. For them, possessive_quantifier
    is always FALSE at this stage.    is always FALSE at this stage. Note that the repeated item starts at
     tempcode, not at previous, which might be the first part of a string whose
     (former) last char we repeated. */
   
     Note that the repeated item starts at tempcode, not at previous, which  
     might be the first part of a string whose (former) last char we repeated.  
   
     Possessifying an 'exact' quantifier has no effect, so we can ignore it. But  
     an 'upto' may follow. We skip over an 'exact' item, and then test the  
     length of what remains before proceeding. */  
   
     if (possessive_quantifier)      if (possessive_quantifier)
       {        {
       int len;        int len;
   
      if (*tempcode == OP_TYPEEXACT)      /* Possessifying an EXACT quantifier has no effect, so we can ignore it.
        tempcode += _pcre_OP_lengths[*tempcode] +      However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6},
          ((tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP)? 2 : 0);      {5,}, or {5,10}). We skip over an EXACT item; if the length of what
       remains is greater than zero, there's a further opcode that can be
       handled. If not, do nothing, leaving the EXACT alone. */
   
      else if (*tempcode == OP_EXACT || *tempcode == OP_NOTEXACT)      switch(*tempcode)
         {          {
        tempcode += _pcre_OP_lengths[*tempcode];        case OP_TYPEEXACT:
#ifdef SUPPORT_UTF8        tempcode += PRIV(OP_lengths)[*tempcode] +
        if (utf8 && tempcode[-1] >= 0xc0)          ((tempcode[1 + IMM2_SIZE] == OP_PROP
          tempcode += _pcre_utf8_table4[tempcode[-1] & 0x3f];          || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
         break;
 
         /* CHAR opcodes are used for exacts whose count is 1. */
 
         case OP_CHAR:
         case OP_CHARI:
         case OP_NOT:
         case OP_NOTI:
         case OP_EXACT:
         case OP_EXACTI:
         case OP_NOTEXACT:
         case OP_NOTEXACTI:
         tempcode += PRIV(OP_lengths)[*tempcode];
 #ifdef SUPPORT_UTF
         if (utf && HAS_EXTRALEN(tempcode[-1]))
           tempcode += GET_EXTRALEN(tempcode[-1]);
 #endif  #endif
           break;
   
           /* For the class opcodes, the repeat operator appears at the end;
           adjust tempcode to point to it. */
   
           case OP_CLASS:
           case OP_NCLASS:
           tempcode += 1 + 32/sizeof(pcre_uchar);
           break;
   
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
           case OP_XCLASS:
           tempcode += GET(tempcode, 1);
           break;
   #endif
         }          }
   
         /* If tempcode is equal to code (which points to the end of the repeated
         item), it means we have skipped an EXACT item but there is no following
         QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In
         all other cases, tempcode will be pointing to the repeat opcode, and will
         be less than code, so the value of len will be greater than 0. */
   
       len = (int)(code - tempcode);        len = (int)(code - tempcode);
         if (len > 0)
           {
           unsigned int repcode = *tempcode;
   
           /* There is a table for possessifying opcodes, all of which are less
           than OP_CALLOUT. A zero entry means there is no possessified version.
           */
   
           if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0)
             *tempcode = opcode_possessify[repcode];
   
           /* For opcode without a special possessified version, wrap the item in
           ONCE brackets. Because we are moving code along, we must ensure that any
           pending recursive references are updated. */
   
           else
             {
             *code = OP_END;
             adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
             memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
             code += 1 + LINK_SIZE;
             len += 1 + LINK_SIZE;
             tempcode[0] = OP_ONCE;
             *code++ = OP_KET;
             PUTINC(code, 0, len);
             PUT(tempcode, 1, len);
             }
           }
   
   #ifdef NEVER
       if (len > 0) switch (*tempcode)        if (len > 0) switch (*tempcode)
         {          {
         case OP_STAR:  *tempcode = OP_POSSTAR; break;          case OP_STAR:  *tempcode = OP_POSSTAR; break;
Line 5250  for (;; ptr++) Line 6333  for (;; ptr++)
         case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break;          case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break;
         case OP_TYPEUPTO:  *tempcode = OP_TYPEPOSUPTO; break;          case OP_TYPEUPTO:  *tempcode = OP_TYPEPOSUPTO; break;
   
           case OP_CRSTAR:   *tempcode = OP_CRPOSSTAR; break;
           case OP_CRPLUS:   *tempcode = OP_CRPOSPLUS; break;
           case OP_CRQUERY:  *tempcode = OP_CRPOSQUERY; break;
           case OP_CRRANGE:  *tempcode = OP_CRPOSRANGE; break;
   
         /* Because we are moving code along, we must ensure that any          /* Because we are moving code along, we must ensure that any
         pending recursive references are updated. */          pending recursive references are updated. */
   
         default:          default:
         *code = OP_END;          *code = OP_END;
        adjust_recurse(tempcode, 1 + LINK_SIZE, utf8, cd, save_hwm);        adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
        memmove(tempcode + 1+LINK_SIZE, tempcode, len);        memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
         code += 1 + LINK_SIZE;          code += 1 + LINK_SIZE;
         len += 1 + LINK_SIZE;          len += 1 + LINK_SIZE;
         tempcode[0] = OP_ONCE;          tempcode[0] = OP_ONCE;
Line 5265  for (;; ptr++) Line 6353  for (;; ptr++)
         PUT(tempcode, 1, len);          PUT(tempcode, 1, len);
         break;          break;
         }          }
   #endif
       }        }
   
     /* In all case we no longer have a previous item. We also set the      /* In all case we no longer have a previous item. We also set the
    "follows varying string" flag for subsequently encountered reqbytes if    "follows varying string" flag for subsequently encountered reqchars if
     it isn't already set and we have just passed a varying length item. */      it isn't already set and we have just passed a varying length item. */
   
     END_REPEAT:      END_REPEAT:
Line 5291  for (;; ptr++) Line 6380  for (;; ptr++)
   
     /* First deal with various "verbs" that can be introduced by '*'. */      /* First deal with various "verbs" that can be introduced by '*'. */
   
    if (*(++ptr) == CHAR_ASTERISK &&    ptr++;
         ((cd->ctypes[ptr[1]] & ctype_letter) != 0 || ptr[1] == ':'))    if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':'
          || (MAX_255(ptr[1]) && ((cd->ctypes[ptr[1]] & ctype_letter) != 0))))
       {        {
       int i, namelen;        int i, namelen;
       int arglen = 0;        int arglen = 0;
       const char *vn = verbnames;        const char *vn = verbnames;
      const uschar *name = ptr + 1;      const pcre_uchar *name = ptr + 1;
      const uschar *arg = NULL;      const pcre_uchar *arg = NULL;
       previous = NULL;        previous = NULL;
      while ((cd->ctypes[*++ptr] & ctype_letter) != 0) {};      ptr++;
       while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
       namelen = (int)(ptr - name);        namelen = (int)(ptr - name);
   
       /* It appears that Perl allows any characters whatsoever, other than        /* It appears that Perl allows any characters whatsoever, other than
Line 5310  for (;; ptr++) Line 6401  for (;; ptr++)
       if (*ptr == CHAR_COLON)        if (*ptr == CHAR_COLON)
         {          {
         arg = ++ptr;          arg = ++ptr;
        while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;        while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
         arglen = (int)(ptr - arg);          arglen = (int)(ptr - arg);
           if ((unsigned int)arglen > MAX_MARK)
             {
             *errorcodeptr = ERR75;
             goto FAILED;
             }
         }          }
   
       if (*ptr != CHAR_RIGHT_PARENTHESIS)        if (*ptr != CHAR_RIGHT_PARENTHESIS)
Line 5325  for (;; ptr++) Line 6421  for (;; ptr++)
       for (i = 0; i < verbcount; i++)        for (i = 0; i < verbcount; i++)
         {          {
         if (namelen == verbs[i].len &&          if (namelen == verbs[i].len &&
            strncmp((char *)name, vn, namelen) == 0)            STRNCMP_UC_C8(name, vn, namelen) == 0)
           {            {
             int setverb;
   
           /* Check for open captures before ACCEPT and convert it to            /* Check for open captures before ACCEPT and convert it to
           ASSERT_ACCEPT if in an assertion. */            ASSERT_ACCEPT if in an assertion. */
   
Line 5344  for (;; ptr++) Line 6442  for (;; ptr++)
               *code++ = OP_CLOSE;                *code++ = OP_CLOSE;
               PUT2INC(code, 0, oc->number);                PUT2INC(code, 0, oc->number);
               }                }
            *code++ = (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;            setverb = *code++ =
               (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
   
            /* Do not set firstbyte after *ACCEPT */            /* Do not set firstchar after *ACCEPT */
            if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;            if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
             }              }
   
           /* Handle other cases with/without an argument */            /* Handle other cases with/without an argument */
Line 5359  for (;; ptr++) Line 6458  for (;; ptr++)
               *errorcodeptr = ERR66;                *errorcodeptr = ERR66;
               goto FAILED;                goto FAILED;
               }                }
            *code = verbs[i].op;            setverb = *code++ = verbs[i].op;
            if (*code++ == OP_THEN) cd->external_flags |= PCRE_HASTHEN; 
             }              }
   
           else            else
Line 5370  for (;; ptr++) Line 6468  for (;; ptr++)
               *errorcodeptr = ERR59;                *errorcodeptr = ERR59;
               goto FAILED;                goto FAILED;
               }                }
            *code = verbs[i].op_arg;            setverb = *code++ = verbs[i].op_arg;
            if (*code++ == OP_THEN_ARG) cd->external_flags |= PCRE_HASTHEN; 
             *code++ = arglen;              *code++ = arglen;
            memcpy(code, arg, arglen);            memcpy(code, arg, IN_UCHARS(arglen));
             code += arglen;              code += arglen;
             *code++ = 0;              *code++ = 0;
             }              }
   
             switch (setverb)
               {
               case OP_THEN:
               case OP_THEN_ARG:
               cd->external_flags |= PCRE_HASTHEN;
               break;
   
               case OP_PRUNE:
               case OP_PRUNE_ARG:
               case OP_SKIP:
               case OP_SKIP_ARG:
               cd->had_pruneorskip = TRUE;
               break;
               }
   
           break;  /* Found verb, exit loop */            break;  /* Found verb, exit loop */
           }            }
   
Line 5396  for (;; ptr++) Line 6508  for (;; ptr++)
       {        {
       int i, set, unset, namelen;        int i, set, unset, namelen;
       int *optset;        int *optset;
      const uschar *name;      const pcre_uchar *name;
      uschar *slot;      pcre_uchar *slot;
   
       switch (*(++ptr))        switch (*(++ptr))
         {          {
         case CHAR_NUMBER_SIGN:                 /* Comment; skip to ket */          case CHAR_NUMBER_SIGN:                 /* Comment; skip to ket */
         ptr++;          ptr++;
        while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;        while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
        if (*ptr == 0)        if (*ptr == CHAR_NULL)
           {            {
           *errorcodeptr = ERR18;            *errorcodeptr = ERR18;
           goto FAILED;            goto FAILED;
Line 5427  for (;; ptr++) Line 6539  for (;; ptr++)
         /* ------------------------------------------------------------ */          /* ------------------------------------------------------------ */
         case CHAR_LEFT_PARENTHESIS:          case CHAR_LEFT_PARENTHESIS:
         bravalue = OP_COND;       /* Conditional group */          bravalue = OP_COND;       /* Conditional group */
           tempptr = ptr;
   
         /* A condition can be an assertion, a number (referring to a numbered          /* A condition can be an assertion, a number (referring to a numbered
        group), a name (referring to a named group), or 'R', referring to        group's having been set), a name (referring to a named group), or 'R',
        recursion. R<digits> and R&name are also permitted for recursion tests.        referring to recursion. R<digits> and R&name are also permitted for
         recursion tests.
   
        There are several syntaxes for testing a named group: (?(name)) is used        There are ways of testing a named group: (?(name)) is used by Python;
        by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')).        Perl 5.10 onwards uses (?(<name>) or (?('name')).
   
        There are two unfortunate ambiguities, caused by history. (a) 'R' can        There is one unfortunate ambiguity, caused by history. 'R' can be the
        be the recursive thing or the name 'R' (and similarly for 'R' followed        recursive thing or the name 'R' (and similarly for 'R' followed by
        by digits), and (b) a number could be a name that consists of digits.        digits). We look for a name first; if not found, we try the other case.
        In both cases, we look for a name first; if not found, we try the other 
        cases. */ 
   
           For compatibility with auto-callouts, we allow a callout to be
           specified before a condition that is an assertion. First, check for the
           syntax of a callout; if found, adjust the temporary pointer that is
           used to check for an assertion condition. That's all that is needed! */
   
           if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C)
             {
             for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
             if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
               tempptr += i + 1;
             }
   
         /* For conditions that are assertions, check the syntax, and then exit          /* For conditions that are assertions, check the syntax, and then exit
         the switch. This will take control down to where bracketed groups,          the switch. This will take control down to where bracketed groups,
         including assertions, are processed. */          including assertions, are processed. */
   
        if (ptr[1] == CHAR_QUESTION_MARK && (ptr[2] == CHAR_EQUALS_SIGN ||        if (tempptr[1] == CHAR_QUESTION_MARK &&
            ptr[2] == CHAR_EXCLAMATION_MARK || ptr[2] == CHAR_LESS_THAN_SIGN))              (tempptr[2] == CHAR_EQUALS_SIGN ||
                tempptr[2] == CHAR_EXCLAMATION_MARK ||
                tempptr[2] == CHAR_LESS_THAN_SIGN))
           break;            break;
   
        /* Most other conditions use OP_CREF (a couple change to OP_RREF        /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all
        below), and all need to skip 3 bytes at the start of the group. */        need to skip at least 1+IMM2_SIZE bytes at the start of the group. */
   
         code[1+LINK_SIZE] = OP_CREF;          code[1+LINK_SIZE] = OP_CREF;
        skipbytes = 3;        skipbytes = 1+IMM2_SIZE;
         refsign = -1;          refsign = -1;
   
         /* Check for a test for recursion in a named group. */          /* Check for a test for recursion in a named group. */
   
        if (ptr[1] == CHAR_R && ptr[2] == CHAR_AMPERSAND)        ptr++;
         if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND)
           {            {
           terminator = -1;            terminator = -1;
           ptr += 2;            ptr += 2;
Line 5466  for (;; ptr++) Line 6593  for (;; ptr++)
           }            }
   
         /* Check for a test for a named group's having been set, using the Perl          /* Check for a test for a named group's having been set, using the Perl
        syntax (?(<name>) or (?('name') */        syntax (?(<name>) or (?('name'), and also allow for the original PCRE
         syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */
   
        else if (ptr[1] == CHAR_LESS_THAN_SIGN)        else if (*ptr == CHAR_LESS_THAN_SIGN)
           {            {
           terminator = CHAR_GREATER_THAN_SIGN;            terminator = CHAR_GREATER_THAN_SIGN;
           ptr++;            ptr++;
           }            }
        else if (ptr[1] == CHAR_APOSTROPHE)        else if (*ptr == CHAR_APOSTROPHE)
           {            {
           terminator = CHAR_APOSTROPHE;            terminator = CHAR_APOSTROPHE;
           ptr++;            ptr++;
           }            }
         else          else
           {            {
          terminator = 0;          terminator = CHAR_NULL;
          if (ptr[1] == CHAR_MINUS || ptr[1] == CHAR_PLUS) refsign = *(++ptr);          if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++;
             else if (IS_DIGIT(*ptr)) refsign = 0;
           }            }
   
        /* We now expect to read a name; any thing else is an error */        /* Handle a number */
   
        if ((cd->ctypes[ptr[1]] & ctype_word) == 0)        if (refsign >= 0)
           {            {
          ptr += 1;  /* To get the right offset */          recno = 0;
          *errorcodeptr = ERR28;          while (IS_DIGIT(*ptr))
          goto FAILED;            {
             recno = recno * 10 + (int)(*ptr - CHAR_0);
             ptr++;
             }
           }            }
   
        /* Read the name, but also get it as a number if it's all digits */        /* Otherwise we expect to read a name; anything else is an error. When
         a name is one of a number of duplicates, a different opcode is used and
         it needs more memory. Unfortunately we cannot tell whether a name is a
         duplicate in the first pass, so we have to allow for more memory. */
   
        recno = 0;        else
        name = ++ptr; 
        while ((cd->ctypes[*ptr] & ctype_word) != 0) 
           {            {
          if (recno >= 0)          if (IS_DIGIT(*ptr))
            recno = ((digitab[*ptr] & ctype_digit) != 0)?            {
              recno * 10 + *ptr - CHAR_0 : -1;            *errorcodeptr = ERR84;
          ptr++;            goto FAILED;
             }
           if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_word) == 0)
             {
             *errorcodeptr = ERR28;   /* Assertion expected */
             goto FAILED;
             }
           name = ptr++;
           while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0)
             {
             ptr++;
             }
           namelen = (int)(ptr - name);
           if (lengthptr != NULL) *lengthptr += IMM2_SIZE;
           }            }
         namelen = (int)(ptr - name);  
   
        if ((terminator > 0 && *ptr++ != terminator) ||        /* Check the terminator */
 
         if ((terminator > 0 && *ptr++ != (pcre_uchar)terminator) ||
             *ptr++ != CHAR_RIGHT_PARENTHESIS)              *ptr++ != CHAR_RIGHT_PARENTHESIS)
           {            {
          ptr--;      /* Error offset */          ptr--;                  /* Error offset */
          *errorcodeptr = ERR26;          *errorcodeptr = ERR26;  /* Malformed number or name */
           goto FAILED;            goto FAILED;
           }            }
   
Line 5519  for (;; ptr++) Line 6666  for (;; ptr++)
         if (lengthptr != NULL) break;          if (lengthptr != NULL) break;
   
         /* In the real compile we do the work of looking for the actual          /* In the real compile we do the work of looking for the actual
        reference. If the string started with "+" or "-" we require the rest to        reference. If refsign is not negative, it means we have a number in
        be digits, in which case recno will be set. */        recno. */
   
        if (refsign > 0)        if (refsign >= 0)
           {            {
           if (recno <= 0)            if (recno <= 0)
             {              {
            *errorcodeptr = ERR58;            *errorcodeptr = ERR35;
             goto FAILED;              goto FAILED;
             }              }
          recno = (refsign == CHAR_MINUS)?          if (refsign != 0) recno = (refsign == CHAR_MINUS)?
            cd->bracount - recno + 1 : recno +cd->bracount;            cd->bracount - recno + 1 : recno + cd->bracount;
           if (recno <= 0 || recno > cd->final_bracount)            if (recno <= 0 || recno > cd->final_bracount)
             {              {
             *errorcodeptr = ERR15;              *errorcodeptr = ERR15;
Line 5540  for (;; ptr++) Line 6687  for (;; ptr++)
           break;            break;
           }            }
   
        /* Otherwise (did not start with "+" or "-"), start by looking for the        /* Otherwise look for the name. */
        name. If we find a name, add one to the opcode to change OP_CREF or 
        OP_RREF into OP_NCREF or OP_NRREF. These behave exactly the same, 
        except they record that the reference was originally to a name. The 
        information is used to check duplicate names. */ 
   
         slot = cd->name_table;          slot = cd->name_table;
         for (i = 0; i < cd->names_found; i++)          for (i = 0; i < cd->names_found; i++)
           {            {
          if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break;          if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0) break;
           slot += cd->name_entry_size;            slot += cd->name_entry_size;
           }            }
   
        /* Found a previous named subpattern */        /* Found the named subpattern. If the name is duplicated, add one to
         the opcode to change CREF/RREF into DNCREF/DNRREF and insert
         appropriate data values. Otherwise, just insert the unique subpattern
         number. */
   
         if (i < cd->names_found)          if (i < cd->names_found)
           {            {
          recno = GET2(slot, 0);          int offset = i++;
          PUT2(code, 2+LINK_SIZE, recno);          int count = 1;
          code[1+LINK_SIZE]++;          recno = GET2(slot, 0);   /* Number from first found */
           for (; i < cd->names_found; i++)
             {
             slot += cd->name_entry_size;
             if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) != 0) break;
             count++;
             }
           if (count > 1)
             {
             PUT2(code, 2+LINK_SIZE, offset);
             PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
             skipbytes += IMM2_SIZE;
             code[1+LINK_SIZE]++;
             }
           else  /* Not a duplicated name */
             {
             PUT2(code, 2+LINK_SIZE, recno);
             }
           }            }
   
        /* Search the pattern for a forward reference */        /* If terminator == CHAR_NULL it means that the name followed directly
         after the opening parenthesis [e.g. (?(abc)...] and in this case there
         are some further alternatives to try. For the cases where terminator !=
         CHAR_NULL [things like (?(<name>... or (?('name')... or (?(R&name)... ]
         we have now checked all the possibilities, so give an error. */
   
        else if ((i = find_parens(cd, name, namelen,        else if (terminator != CHAR_NULL)
                        (options & PCRE_EXTENDED) != 0, utf8)) > 0) 
           {            {
           PUT2(code, 2+LINK_SIZE, i);  
           code[1+LINK_SIZE]++;  
           }  
   
         /* If terminator == 0 it means that the name followed directly after  
         the opening parenthesis [e.g. (?(abc)...] and in this case there are  
         some further alternatives to try. For the cases where terminator != 0  
         [things like (?(<name>... or (?('name')... or (?(R&name)... ] we have  
         now checked all the possibilities, so give an error. */  
   
         else if (terminator != 0)  
           {  
           *errorcodeptr = ERR15;            *errorcodeptr = ERR15;
           goto FAILED;            goto FAILED;
           }            }
Line 5591  for (;; ptr++) Line 6745  for (;; ptr++)
           recno = 0;            recno = 0;
           for (i = 1; i < namelen; i++)            for (i = 1; i < namelen; i++)
             {              {
            if ((digitab[name[i]] & ctype_digit) == 0)            if (!IS_DIGIT(name[i]))
               {                {
               *errorcodeptr = ERR15;                *errorcodeptr = ERR15;
               goto FAILED;                goto FAILED;
Line 5606  for (;; ptr++) Line 6760  for (;; ptr++)
         /* Similarly, check for the (?(DEFINE) "condition", which is always          /* Similarly, check for the (?(DEFINE) "condition", which is always
         false. */          false. */
   
        else if (namelen == 6 && strncmp((char *)name, STRING_DEFINE, 6) == 0)        else if (namelen == 6 && STRNCMP_UC_C8(name, STRING_DEFINE, 6) == 0)
           {            {
           code[1+LINK_SIZE] = OP_DEF;            code[1+LINK_SIZE] = OP_DEF;
           skipbytes = 1;            skipbytes = 1;
           }            }
   
        /* Check for the "name" actually being a subpattern number. We are        /* Reference to an unidentified subpattern. */
        in the second pass here, so final_bracount is set. */ 
   
         else if (recno > 0 && recno <= cd->final_bracount)  
           {  
           PUT2(code, 2+LINK_SIZE, recno);  
           }  
   
         /* Either an unidentified subpattern, or a reference to (?(0) */  
   
         else          else
           {            {
          *errorcodeptr = (recno == 0)? ERR35: ERR15;          *errorcodeptr = ERR15;
           goto FAILED;            goto FAILED;
           }            }
         break;          break;
Line 5637  for (;; ptr++) Line 6783  for (;; ptr++)
         ptr++;          ptr++;
         break;          break;
   
           /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird
           thing to do, but Perl allows all assertions to be quantified, and when
           they contain capturing parentheses there may be a potential use for
           this feature. Not that that applies to a quantified (?!) but we allow
           it for uniformity. */
   
         /* ------------------------------------------------------------ */          /* ------------------------------------------------------------ */
         case CHAR_EXCLAMATION_MARK:            /* Negative lookahead */          case CHAR_EXCLAMATION_MARK:            /* Negative lookahead */
         ptr++;          ptr++;
        if (*ptr == CHAR_RIGHT_PARENTHESIS)    /* Optimize (?!) */        if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK &&
              ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK &&
             (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2)))
           {            {
           *code++ = OP_FAIL;            *code++ = OP_FAIL;
           previous = NULL;            previous = NULL;
Line 5669  for (;; ptr++) Line 6822  for (;; ptr++)
           break;            break;
   
           default:                /* Could be name define, else bad */            default:                /* Could be name define, else bad */
          if ((cd->ctypes[ptr[1]] & ctype_word) != 0) goto DEFINE_NAME;          if (MAX_255(ptr[1]) && (cd->ctypes[ptr[1]] & ctype_word) != 0)
             goto DEFINE_NAME;
           ptr++;                  /* Correct offset for error */            ptr++;                  /* Correct offset for error */
           *errorcodeptr = ERR24;            *errorcodeptr = ERR24;
           goto FAILED;            goto FAILED;
Line 5691  for (;; ptr++) Line 6845  for (;; ptr++)
         *code++ = OP_CALLOUT;          *code++ = OP_CALLOUT;
           {            {
           int n = 0;            int n = 0;
          while ((digitab[*(++ptr)] & ctype_digit) != 0)          ptr++;
            n = n * 10 + *ptr - CHAR_0;          while(IS_DIGIT(*ptr))
             n = n * 10 + *ptr++ - CHAR_0;
           if (*ptr != CHAR_RIGHT_PARENTHESIS)            if (*ptr != CHAR_RIGHT_PARENTHESIS)
             {              {
             *errorcodeptr = ERR39;              *errorcodeptr = ERR39;
Line 5732  for (;; ptr++) Line 6887  for (;; ptr++)
         /* ------------------------------------------------------------ */          /* ------------------------------------------------------------ */
         DEFINE_NAME:    /* Come here from (?< handling */          DEFINE_NAME:    /* Come here from (?< handling */
         case CHAR_APOSTROPHE:          case CHAR_APOSTROPHE:
           terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
             CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
           name = ++ptr;
           if (IS_DIGIT(*ptr))
           {            {
          terminator = (*ptr == CHAR_LESS_THAN_SIGN)?          *errorcodeptr = ERR84;   /* Group name must start with non-digit */
            CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;          goto FAILED;
          name = ++ptr;          }
         while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
         namelen = (int)(ptr - name);
   
          while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;        /* In the pre-compile phase, do a syntax check, remember the longest
          namelen = (int)(ptr - name);        name, and then remember the group in a vector, expanding it if
         necessary. Duplicates for the same number are skipped; other duplicates
         are checked for validity. In the actual compile, there is nothing to
         do. */
   
          /* In the pre-compile phase, just do a syntax check. */        if (lengthptr != NULL)
           {
           named_group *ng;
           pcre_uint32 number = cd->bracount + 1;
   
          if (lengthptr != NULL)          if (*ptr != (pcre_uchar)terminator)
             {              {
            if (*ptr != terminator)            *errorcodeptr = ERR42;
             goto FAILED;
             }
 
           if (cd->names_found >= MAX_NAME_COUNT)
             {
             *errorcodeptr = ERR49;
             goto FAILED;
             }
 
           if (namelen + IMM2_SIZE + 1 > cd->name_entry_size)
             {
             cd->name_entry_size = namelen + IMM2_SIZE + 1;
             if (namelen > MAX_NAME_SIZE)
               {                {
              *errorcodeptr = ERR42;              *errorcodeptr = ERR48;
               goto FAILED;                goto FAILED;
               }                }
            if (cd->names_found >= MAX_NAME_COUNT)            }
 
           /* Scan the list to check for duplicates. For duplicate names, if the
           number is the same, break the loop, which causes the name to be
           discarded; otherwise, if DUPNAMES is not set, give an error.
           If it is set, allow the name with a different number, but continue
           scanning in case this is a duplicate with the same number. For
           non-duplicate names, give an error if the number is duplicated. */
 
           ng = cd->named_groups;
           for (i = 0; i < cd->names_found; i++, ng++)
             {
             if (namelen == ng->length &&
                 STRNCMP_UC_UC(name, ng->name, namelen) == 0)
               {                {
              *errorcodeptr = ERR49;              if (ng->number == number) break;
              goto FAILED;              if ((options & PCRE_DUPNAMES) == 0)
              } 
            if (namelen + 3 > cd->name_entry_size) 
              { 
              cd->name_entry_size = namelen + 3; 
              if (namelen > MAX_NAME_SIZE) 
                 {                  {
                *errorcodeptr = ERR48;                *errorcodeptr = ERR43;
                 goto FAILED;                  goto FAILED;
                 }                  }
                 cd->dupnames = TRUE;  /* Duplicate names exist */
               }                }
               else if (ng->number == number)
                 {
                 *errorcodeptr = ERR65;
                 goto FAILED;
                 }
             }              }
   
          /* In the real compile, create the entry in the table, maintaining          if (i >= cd->names_found)     /* Not a duplicate with same number */
          alphabetical order. Duplicate names for different numbers are 
          permitted only if PCRE_DUPNAMES is set. Duplicate names for the same 
          number are always OK. (An existing number can be re-used if (?| 
          appears in the pattern.) In either event, a duplicate name results in 
          a duplicate entry in the table, even if the number is the same. This 
          is because the number of names, and hence the table size, is computed 
          in the pre-compile, and it affects various numbers and pointers which 
          would all have to be modified, and the compiled code moved down, if 
          duplicates with the same number were omitted from the table. This 
          doesn't seem worth the hassle. However, *different* names for the 
          same number are not permitted. */ 
 
          else 
             {              {
            BOOL dupname = FALSE;            /* Increase the list size if necessary */
            slot = cd->name_table; 
   
            for (i = 0; i < cd->names_found; i++)            if (cd->names_found >= cd->named_group_list_size)
               {                {
              int crc = memcmp(name, slot+2, namelen);              int newsize = cd->named_group_list_size * 2;
              if (crc == 0)              named_group *newspace = (PUBL(malloc))
                {                (newsize * sizeof(named_group));
                if (slot[2+namelen] == 0) 
                  { 
                  if (GET2(slot, 0) != cd->bracount + 1 && 
                      (options & PCRE_DUPNAMES) == 0) 
                    { 
                    *errorcodeptr = ERR43; 
                    goto FAILED; 
                    } 
                  else dupname = TRUE; 
                  } 
                else crc = -1;      /* Current name is a substring */ 
                } 
   
              /* Make space in the table and break the loop for an earlier              if (newspace == NULL)
              name. For a duplicate or later name, carry on. We do this for 
              duplicates so that in the simple case (when ?(| is not used) they 
              are in order of their numbers. */ 
 
              if (crc < 0) 
                 {                  {
                memmove(slot + cd->name_entry_size, slot,                *errorcodeptr = ERR21;
                  (cd->names_found - i) * cd->name_entry_size);                goto FAILED;
                break; 
                 }                  }
   
              /* Continue the loop for a later or duplicate name */              memcpy(newspace, cd->named_groups,
                cd->named_group_list_size * sizeof(named_group));
              slot += cd->name_entry_size;              if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE)
                 (PUBL(free))((void *)cd->named_groups);
               cd->named_groups = newspace;
               cd->named_group_list_size = newsize;
               }                }
   
            /* For non-duplicate names, check for a duplicate number before            cd->named_groups[cd->names_found].name = name;
            adding the new name. */            cd->named_groups[cd->names_found].length = namelen;
            cd->named_groups[cd->names_found].number = number;
            if (!dupname)            cd->names_found++;
              { 
              uschar *cslot = cd->name_table; 
              for (i = 0; i < cd->names_found; i++) 
                { 
                if (cslot != slot) 
                  { 
                  if (GET2(cslot, 0) == cd->bracount + 1) 
                    { 
                    *errorcodeptr = ERR65; 
                    goto FAILED; 
                    } 
                  } 
                else i--; 
                cslot += cd->name_entry_size; 
                } 
              } 
 
            PUT2(slot, 0, cd->bracount + 1); 
            memcpy(slot + 2, name, namelen); 
            slot[2+namelen] = 0; 
             }              }
           }            }
   
        /* In both pre-compile and compile, count the number of names we've        ptr++;                    /* Move past > or ' in both passes. */
        encountered. */ 
 
        cd->names_found++; 
        ptr++;                    /* Move past > or ' */ 
         goto NUMBERED_GROUP;          goto NUMBERED_GROUP;
   
   
Line 5867  for (;; ptr++) Line 7008  for (;; ptr++)
   
         NAMED_REF_OR_RECURSE:          NAMED_REF_OR_RECURSE:
         name = ++ptr;          name = ++ptr;
        while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;        if (IS_DIGIT(*ptr))
           {
           *errorcodeptr = ERR84;   /* Group name must start with non-digit */
           goto FAILED;
           }
         while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
         namelen = (int)(ptr - name);          namelen = (int)(ptr - name);
   
         /* In the pre-compile phase, do a syntax check. We used to just set          /* In the pre-compile phase, do a syntax check. We used to just set
Line 5879  for (;; ptr++) Line 7025  for (;; ptr++)
   
         if (lengthptr != NULL)          if (lengthptr != NULL)
           {            {
          const uschar *temp;          named_group *ng;
   
           if (namelen == 0)            if (namelen == 0)
             {              {
             *errorcodeptr = ERR62;              *errorcodeptr = ERR62;
             goto FAILED;              goto FAILED;
             }              }
          if (*ptr != terminator)          if (*ptr != (pcre_uchar)terminator)
             {              {
             *errorcodeptr = ERR42;              *errorcodeptr = ERR42;
             goto FAILED;              goto FAILED;
Line 5897  for (;; ptr++) Line 7043  for (;; ptr++)
             goto FAILED;              goto FAILED;
             }              }
   
          /* The name table does not exist in the first pass, so we cannot          /* The name table does not exist in the first pass; instead we must
          do a simple search as in the code below. Instead, we have to scan the          scan the list of names encountered so far in order to get the
          pattern to find the number. It is important that we scan it only as          number. If the name is not found, set the value to 0 for a forward
          far as we have got because the syntax of named subpatterns has not          reference. */
          been checked for the rest of the pattern, and find_parens() assumes 
          correct syntax. In any case, it's a waste of resources to scan 
          further. We stop the scan at the current point by temporarily 
          adjusting the value of cd->endpattern. */ 
   
          temp = cd->end_pattern;          ng = cd->named_groups;
          cd->end_pattern = ptr;          for (i = 0; i < cd->names_found; i++, ng++)
          recno = find_parens(cd, name, namelen,            {
            (options & PCRE_EXTENDED) != 0, utf8);            if (namelen == ng->length &&
          cd->end_pattern = temp;                STRNCMP_UC_UC(name, ng->name, namelen) == 0)
          if (recno < 0) recno = 0;    /* Forward ref; set dummy number */              break;
             }
           recno = (i < cd->names_found)? ng->number : 0;
 
           /* Count named back references. */
 
           if (!is_recurse) cd->namedrefcount++;
           }            }
   
        /* In the real compile, seek the name in the table. We check the name        /* In the real compile, search the name table. We check the name
         first, and then check that we have reached the end of the name in the          first, and then check that we have reached the end of the name in the
        table. That way, if the name that is longer than any in the table,        table. That way, if the name is longer than any in the table, the
        the comparison will fail without reading beyond the table entry. */        comparison will fail without reading beyond the table entry. */
   
         else          else
           {            {
           slot = cd->name_table;            slot = cd->name_table;
           for (i = 0; i < cd->names_found; i++)            for (i = 0; i < cd->names_found; i++)
             {              {
            if (strncmp((char *)name, (char *)slot+2, namelen) == 0 &&            if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0 &&
                slot[2+namelen] == 0)                slot[IMM2_SIZE+namelen] == 0)
               break;                break;
             slot += cd->name_entry_size;              slot += cd->name_entry_size;
             }              }
   
          if (i < cd->names_found)         /* Back reference */          if (i < cd->names_found)
             {              {
             recno = GET2(slot, 0);              recno = GET2(slot, 0);
             }              }
          else if ((recno =                /* Forward back reference */          else
                    find_parens(cd, name, namelen, 
                      (options & PCRE_EXTENDED) != 0, utf8)) <= 0) 
             {              {
             *errorcodeptr = ERR15;              *errorcodeptr = ERR15;
             goto FAILED;              goto FAILED;
             }              }
           }            }
   
        /* In both phases, we can now go to the code than handles numerical        /* In both phases, for recursions, we can now go to the code than
        recursion or backreferences. */        handles numerical recursion. */
   
         if (is_recurse) goto HANDLE_RECURSION;          if (is_recurse) goto HANDLE_RECURSION;
           else goto HANDLE_REFERENCE;  
   
           /* In the second pass we must see if the name is duplicated. If so, we
           generate a different opcode. */
   
           if (lengthptr == NULL && cd->dupnames)
             {
             int count = 1;
             unsigned int index = i;
             pcre_uchar *cslot = slot + cd->name_entry_size;
   
             for (i++; i < cd->names_found; i++)
               {
               if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break;
               count++;
               cslot += cd->name_entry_size;
               }
   
             if (count > 1)
               {
               if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
               previous = code;
               *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
               PUT2INC(code, 0, index);
               PUT2INC(code, 0, count);
   
               /* Process each potentially referenced group. */
   
               for (; slot < cslot; slot += cd->name_entry_size)
                 {
                 open_capitem *oc;
                 recno = GET2(slot, 0);
                 cd->backref_map |= (recno < 32)? (1 << recno) : 1;
                 if (recno > cd->top_backref) cd->top_backref = recno;
   
                 /* Check to see if this back reference is recursive, that it, it
                 is inside the group that it references. A flag is set so that the
                 group can be made atomic. */
   
                 for (oc = cd->open_caps; oc != NULL; oc = oc->next)
                   {
                   if (oc->number == recno)
                     {
                     oc->flag = TRUE;
                     break;
                     }
                   }
                 }
   
               continue;  /* End of back ref handling */
               }
             }
   
           /* First pass, or a non-duplicated name. */
   
           goto HANDLE_REFERENCE;
   
   
         /* ------------------------------------------------------------ */          /* ------------------------------------------------------------ */
         case CHAR_R:              /* Recursion */          case CHAR_R:              /* Recursion */
         ptr++;                    /* Same as (?0)      */          ptr++;                    /* Same as (?0)      */
Line 5961  for (;; ptr++) Line 7161  for (;; ptr++)
         case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:          case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
         case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:          case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
           {            {
          const uschar *called;          const pcre_uchar *called;
           terminator = CHAR_RIGHT_PARENTHESIS;            terminator = CHAR_RIGHT_PARENTHESIS;
   
           /* Come here from the \g<...> and \g'...' code (Oniguruma            /* Come here from the \g<...> and \g'...' code (Oniguruma
Line 5975  for (;; ptr++) Line 7175  for (;; ptr++)
           if ((refsign = *ptr) == CHAR_PLUS)            if ((refsign = *ptr) == CHAR_PLUS)
             {              {
             ptr++;              ptr++;
            if ((digitab[*ptr] & ctype_digit) == 0)            if (!IS_DIGIT(*ptr))
               {                {
               *errorcodeptr = ERR63;                *errorcodeptr = ERR63;
               goto FAILED;                goto FAILED;
Line 5983  for (;; ptr++) Line 7183  for (;; ptr++)
             }              }
           else if (refsign == CHAR_MINUS)            else if (refsign == CHAR_MINUS)
             {              {
            if ((digitab[ptr[1]] & ctype_digit) == 0)            if (!IS_DIGIT(ptr[1]))
               goto OTHER_CHAR_AFTER_QUERY;                goto OTHER_CHAR_AFTER_QUERY;
             ptr++;              ptr++;
             }              }
   
           recno = 0;            recno = 0;
          while((digitab[*ptr] & ctype_digit) != 0)          while(IS_DIGIT(*ptr))
             recno = recno * 10 + *ptr++ - CHAR_0;              recno = recno * 10 + *ptr++ - CHAR_0;
   
          if (*ptr != terminator)          if (*ptr != (pcre_uchar)terminator)
             {              {
             *errorcodeptr = ERR29;              *errorcodeptr = ERR29;
             goto FAILED;              goto FAILED;
Line 6040  for (;; ptr++) Line 7240  for (;; ptr++)
             {              {
             *code = OP_END;              *code = OP_END;
             if (recno != 0)              if (recno != 0)
              called = _pcre_find_bracket(cd->start_code, utf8, recno);              called = PRIV(find_bracket)(cd->start_code, utf, recno);
   
             /* Forward reference */              /* Forward reference */
   
             if (called == NULL)              if (called == NULL)
               {                {
              if (find_parens(cd, NULL, recno,              if (recno > cd->final_bracount)
                    (options & PCRE_EXTENDED) != 0, utf8) < 0) 
                 {                  {
                 *errorcodeptr = ERR15;                  *errorcodeptr = ERR15;
                 goto FAILED;                  goto FAILED;
Line 6077  for (;; ptr++) Line 7276  for (;; ptr++)
             conditional subpatterns will be picked up then. */              conditional subpatterns will be picked up then. */
   
             else if (GET(called, 1) == 0 && cond_depth <= 0 &&              else if (GET(called, 1) == 0 && cond_depth <= 0 &&
                     could_be_empty(called, code, bcptr, utf8, cd))                     could_be_empty(called, code, bcptr, utf, cd))
               {                {
               *errorcodeptr = ERR40;                *errorcodeptr = ERR40;
               goto FAILED;                goto FAILED;
Line 6085  for (;; ptr++) Line 7284  for (;; ptr++)
             }              }
   
           /* Insert the recursion/subroutine item. It does not have a set first            /* Insert the recursion/subroutine item. It does not have a set first
          byte (relevant if it is repeated, because it will then be wrapped          character (relevant if it is repeated, because it will then be
          with ONCE brackets). */          wrapped with ONCE brackets). */
   
           *code = OP_RECURSE;            *code = OP_RECURSE;
           PUT(code, 1, (int)(called - cd->start_code));            PUT(code, 1, (int)(called - cd->start_code));
           code += 1 + LINK_SIZE;            code += 1 + LINK_SIZE;
          groupsetfirstbyte = FALSE;          groupsetfirstchar = FALSE;
           }            }
   
         /* Can't determine a first byte now */          /* Can't determine a first byte now */
   
        if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;        if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
         continue;          continue;
   
   
Line 6153  for (;; ptr++) Line 7352  for (;; ptr++)
         both phases.          both phases.
   
         If we are not at the pattern start, reset the greedy defaults and the          If we are not at the pattern start, reset the greedy defaults and the
        case value for firstbyte and reqbyte. */        case value for firstchar and reqchar. */
   
         if (*ptr == CHAR_RIGHT_PARENTHESIS)          if (*ptr == CHAR_RIGHT_PARENTHESIS)
           {            {
Line 6166  for (;; ptr++) Line 7365  for (;; ptr++)
             {              {
             greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);              greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
             greedy_non_default = greedy_default ^ 1;              greedy_non_default = greedy_default ^ 1;
            req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;            req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
             }              }
   
           /* Change options at this level, and pass them back for use            /* Change options at this level, and pass them back for use
Line 6203  for (;; ptr++) Line 7402  for (;; ptr++)
       NUMBERED_GROUP:        NUMBERED_GROUP:
       cd->bracount += 1;        cd->bracount += 1;
       PUT2(code, 1+LINK_SIZE, cd->bracount);        PUT2(code, 1+LINK_SIZE, cd->bracount);
      skipbytes = 2;      skipbytes = IMM2_SIZE;
       }        }
   
    /* Process nested bracketed regex. Assertions used not to be repeatable,    /* Process nested bracketed regex. First check for parentheses nested too
    but this was changed for Perl compatibility, so all kinds can now be    deeply. */
    repeated. We copy code into a non-register variable (tempcode) in order to 
    be able to pass its address because some compilers complain otherwise. */ 
   
       if ((cd->parens_depth += 1) > PARENS_NEST_LIMIT)
         {
         *errorcodeptr = ERR82;
         goto FAILED;
         }
   
       /* Assertions used not to be repeatable, but this was changed for Perl
       compatibility, so all kinds can now be repeated. We copy code into a
       non-register variable (tempcode) in order to be able to pass its address
       because some compilers complain otherwise. */
   
     previous = code;                      /* For handling repetition */      previous = code;                      /* For handling repetition */
     *code = bravalue;      *code = bravalue;
     tempcode = code;      tempcode = code;
Line 6229  for (;; ptr++) Line 7437  for (;; ptr++)
          skipbytes,                       /* Skip over bracket number */           skipbytes,                       /* Skip over bracket number */
          cond_depth +           cond_depth +
            ((bravalue == OP_COND)?1:0),   /* Depth of condition subpatterns */             ((bravalue == OP_COND)?1:0),   /* Depth of condition subpatterns */
         &subfirstbyte,                   /* For possible first char */         &subfirstchar,                   /* For possible first char */
         &subreqbyte,                     /* For possible last char */         &subfirstcharflags,
          &subreqchar,                     /* For possible last char */
          &subreqcharflags,
          bcptr,                           /* Current branch chain */           bcptr,                           /* Current branch chain */
          cd,                              /* Tables block */           cd,                              /* Tables block */
          (lengthptr == NULL)? NULL :      /* Actual compile phase */           (lengthptr == NULL)? NULL :      /* Actual compile phase */
Line 6238  for (;; ptr++) Line 7448  for (;; ptr++)
          ))           ))
       goto FAILED;        goto FAILED;
   
       cd->parens_depth -= 1;
   
     /* If this was an atomic group and there are no capturing groups within it,      /* If this was an atomic group and there are no capturing groups within it,
     generate OP_ONCE_NC instead of OP_ONCE. */      generate OP_ONCE_NC instead of OP_ONCE. */
   
Line 6258  for (;; ptr++) Line 7470  for (;; ptr++)
   
     if (bravalue == OP_COND && lengthptr == NULL)      if (bravalue == OP_COND && lengthptr == NULL)
       {        {
      uschar *tc = code;      pcre_uchar *tc = code;
       int condcount = 0;        int condcount = 0;
   
       do {        do {
Line 6281  for (;; ptr++) Line 7493  for (;; ptr++)
         }          }
   
       /* A "normal" conditional group. If there is just one branch, we must not        /* A "normal" conditional group. If there is just one branch, we must not
      make use of its firstbyte or reqbyte, because this is equivalent to an      make use of its firstchar or reqchar, because this is equivalent to an
       empty second branch. */        empty second branch. */
   
       else        else
Line 6291  for (;; ptr++) Line 7503  for (;; ptr++)
           *errorcodeptr = ERR27;            *errorcodeptr = ERR27;
           goto FAILED;            goto FAILED;
           }            }
        if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE;        if (condcount == 1) subfirstcharflags = subreqcharflags = REQ_NONE;
         }          }
       }        }
   
Line 6335  for (;; ptr++) Line 7547  for (;; ptr++)
     /* Handle updating of the required and first characters for other types of      /* Handle updating of the required and first characters for other types of
     group. Update for normal brackets of all kinds, and conditions with two      group. Update for normal brackets of all kinds, and conditions with two
     branches (see code above). If the bracket is followed by a quantifier with      branches (see code above). If the bracket is followed by a quantifier with
    zero repeat, we have to back off. Hence the definition of zeroreqbyte and    zero repeat, we have to back off. Hence the definition of zeroreqchar and
    zerofirstbyte outside the main loop so that they can be accessed for the    zerofirstchar outside the main loop so that they can be accessed for the
     back off. */      back off. */
   
    zeroreqbyte = reqbyte;    zeroreqchar = reqchar;
    zerofirstbyte = firstbyte;    zeroreqcharflags = reqcharflags;
    groupsetfirstbyte = FALSE;    zerofirstchar = firstchar;
     zerofirstcharflags = firstcharflags;
     groupsetfirstchar = FALSE;
   
     if (bravalue >= OP_ONCE)      if (bravalue >= OP_ONCE)
       {        {
      /* If we have not yet set a firstbyte in this branch, take it from the      /* If we have not yet set a firstchar in this branch, take it from the
       subpattern, remembering that it was set here so that a repeat of more        subpattern, remembering that it was set here so that a repeat of more
      than one can replicate it as reqbyte if necessary. If the subpattern has      than one can replicate it as reqchar if necessary. If the subpattern has
      no firstbyte, set "none" for the whole branch. In both cases, a zero      no firstchar, set "none" for the whole branch. In both cases, a zero
      repeat forces firstbyte to "none". */      repeat forces firstchar to "none". */
   
      if (firstbyte == REQ_UNSET)      if (firstcharflags == REQ_UNSET)
         {          {
        if (subfirstbyte >= 0)        if (subfirstcharflags >= 0)
           {            {
          firstbyte = subfirstbyte;          firstchar = subfirstchar;
          groupsetfirstbyte = TRUE;          firstcharflags = subfirstcharflags;
           groupsetfirstchar = TRUE;
           }            }
        else firstbyte = REQ_NONE;        else firstcharflags = REQ_NONE;
        zerofirstbyte = REQ_NONE;        zerofirstcharflags = REQ_NONE;
         }          }
   
      /* If firstbyte was previously set, convert the subpattern's firstbyte      /* If firstchar was previously set, convert the subpattern's firstchar
      into reqbyte if there wasn't one, using the vary flag that was in      into reqchar if there wasn't one, using the vary flag that was in
       existence beforehand. */        existence beforehand. */
   
      else if (subfirstbyte >= 0 && subreqbyte < 0)      else if (subfirstcharflags >= 0 && subreqcharflags < 0)
        subreqbyte = subfirstbyte | tempreqvary;        {
         subreqchar = subfirstchar;
         subreqcharflags = subfirstcharflags | tempreqvary;
         }
   
       /* If the subpattern set a required byte (or set a first byte that isn't        /* If the subpattern set a required byte (or set a first byte that isn't
       really the first byte - see above), set it. */        really the first byte - see above), set it. */
   
      if (subreqbyte >= 0) reqbyte = subreqbyte;      if (subreqcharflags >= 0)
         {
         reqchar = subreqchar;
         reqcharflags = subreqcharflags;
         }
       }        }
   
    /* For a forward assertion, we take the reqbyte, if set. This can be    /* For a forward assertion, we take the reqchar, if set. This can be
     helpful if the pattern that follows the assertion doesn't set a different      helpful if the pattern that follows the assertion doesn't set a different
    char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte    char. For example, it's useful for /(?=abcde).+/. We can't set firstchar
     for an assertion, however because it leads to incorrect effect for patterns      for an assertion, however because it leads to incorrect effect for patterns
    such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead    such as /(?=a)a.+/ when the "real" "a" would then become a reqchar instead
    of a firstbyte. This is overcome by a scan at the end if there's no    of a firstchar. This is overcome by a scan at the end if there's no
    firstbyte, looking for an asserted first char. */    firstchar, looking for an asserted first char. */
   
    else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte;    else if (bravalue == OP_ASSERT && subreqcharflags >= 0)
       {
       reqchar = subreqchar;
       reqcharflags = subreqcharflags;
       }
     break;     /* End of processing '(' */      break;     /* End of processing '(' */
   
   
Line 6391  for (;; ptr++) Line 7617  for (;; ptr++)
     /* Handle metasequences introduced by \. For ones like \d, the ESC_ values      /* Handle metasequences introduced by \. For ones like \d, the ESC_ values
     are arranged to be the negation of the corresponding OP_values in the      are arranged to be the negation of the corresponding OP_values in the
     default case when PCRE_UCP is not set. For the back references, the values      default case when PCRE_UCP is not set. For the back references, the values
    are ESC_REF plus the reference number. Only back references and those types    are negative the reference number. Only back references and those types
     that consume a character may be repeated. We can test for values between      that consume a character may be repeated. We can test for values between
     ESC_b and ESC_Z for the latter; this may have to change if any new ones are      ESC_b and ESC_Z for the latter; this may have to change if any new ones are
     ever created. */      ever created. */
   
     case CHAR_BACKSLASH:      case CHAR_BACKSLASH:
     tempptr = ptr;      tempptr = ptr;
    c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE);    escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, FALSE);
     if (*errorcodeptr != 0) goto FAILED;      if (*errorcodeptr != 0) goto FAILED;
   
    if (c < 0)    if (escape == 0)                  /* The escape coded a single character */
       c = ec;
     else
       {        {
      if (-c == ESC_Q)            /* Handle start of quoted string */      if (escape == ESC_Q)            /* Handle start of quoted string */
         {          {
         if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)          if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
           ptr += 2;               /* avoid empty string */            ptr += 2;               /* avoid empty string */
Line 6411  for (;; ptr++) Line 7639  for (;; ptr++)
         continue;          continue;
         }          }
   
      if (-c == ESC_E) continue;  /* Perl ignores an orphan \E */      if (escape == ESC_E) continue;  /* Perl ignores an orphan \E */
   
       /* For metasequences that actually match a character, we disable the        /* For metasequences that actually match a character, we disable the
       setting of a first character if it hasn't already been set. */        setting of a first character if it hasn't already been set. */
   
      if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z)      if (firstcharflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z)
        firstbyte = REQ_NONE;        firstcharflags = REQ_NONE;
   
       /* Set values to reset to if this is followed by a zero repeat. */        /* Set values to reset to if this is followed by a zero repeat. */
   
      zerofirstbyte = firstbyte;      zerofirstchar = firstchar;
      zeroreqbyte = reqbyte;      zerofirstcharflags = firstcharflags;
       zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
   
       /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'        /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'
       is a subroutine call by number (Oniguruma syntax). In fact, the value        is a subroutine call by number (Oniguruma syntax). In fact, the value
      -ESC_g is returned only for these cases. So we don't need to check for <      ESC_g is returned only for these cases. So we don't need to check for <
      or ' if the value is -ESC_g. For the Perl syntax \g{n} the value is      or ' if the value is ESC_g. For the Perl syntax \g{n} the value is
      -ESC_REF+n, and for the Perl syntax \g{name} the result is -ESC_k (as      -n, and for the Perl syntax \g{name} the result is ESC_k (as
       that is a synonym for a named back reference). */        that is a synonym for a named back reference). */
   
      if (-c == ESC_g)      if (escape == ESC_g)
         {          {
        const uschar *p;        const pcre_uchar *p;
         pcre_uint32 cf;
 
         save_hwm = cd->hwm;   /* Normally this is set when '(' is read */          save_hwm = cd->hwm;   /* Normally this is set when '(' is read */
         terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?          terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
           CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;            CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
   
         /* These two statements stop the compiler for warning about possibly          /* These two statements stop the compiler for warning about possibly
         unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In          unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In
        fact, because we actually check for a number below, the paths that        fact, because we do the check for a number below, the paths that
         would actually be in error are never taken. */          would actually be in error are never taken. */
   
         skipbytes = 0;          skipbytes = 0;
         reset_bracount = FALSE;          reset_bracount = FALSE;
   
        /* Test for a name */        /* If it's not a signed or unsigned number, treat it as a name. */
   
        if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS)        cf = ptr[1];
         if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf))
           {            {
           BOOL isnumber = TRUE;  
           for (p = ptr + 1; *p != 0 && *p != terminator; p++)  
             {  
             if ((cd->ctypes[*p] & ctype_digit) == 0) isnumber = FALSE;  
             if ((cd->ctypes[*p] & ctype_word) == 0) break;  
             }  
           if (*p != terminator)  
             {  
             *errorcodeptr = ERR57;  
             break;  
             }  
           if (isnumber)  
             {  
             ptr++;  
             goto HANDLE_NUMERICAL_RECURSION;  
             }  
           is_recurse = TRUE;            is_recurse = TRUE;
           goto NAMED_REF_OR_RECURSE;            goto NAMED_REF_OR_RECURSE;
           }            }
   
        /* Test a signed number in angle brackets or quotes. */        /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus
         or a digit. */
   
         p = ptr + 2;          p = ptr + 2;
        while ((digitab[*p] & ctype_digit) != 0) p++;        while (IS_DIGIT(*p)) p++;
        if (*p != terminator)        if (*p != (pcre_uchar)terminator)
           {            {
           *errorcodeptr = ERR57;            *errorcodeptr = ERR57;
           break;            break;
Line 6486  for (;; ptr++) Line 7704  for (;; ptr++)
       /* \k<name> or \k'name' is a back reference by name (Perl syntax).        /* \k<name> or \k'name' is a back reference by name (Perl syntax).
       We also support \k{name} (.NET syntax).  */        We also support \k{name} (.NET syntax).  */
   
      if (-c == ESC_k)      if (escape == ESC_k)
         {          {
         if ((ptr[1] != CHAR_LESS_THAN_SIGN &&          if ((ptr[1] != CHAR_LESS_THAN_SIGN &&
           ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))            ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))
Line 6501  for (;; ptr++) Line 7719  for (;; ptr++)
         goto NAMED_REF_OR_RECURSE;          goto NAMED_REF_OR_RECURSE;
         }          }
   
      /* Back references are handled specially; must disable firstbyte if      /* Back references are handled specially; must disable firstchar if
       not set to cope with cases like (?=(\w+))\1: which would otherwise set        not set to cope with cases like (?=(\w+))\1: which would otherwise set
       ':' later. */        ':' later. */
   
      if (-c >= ESC_REF)      if (escape < 0)
         {          {
         open_capitem *oc;          open_capitem *oc;
        recno = -c - ESC_REF;        recno = -escape;
   
        HANDLE_REFERENCE:    /* Come here from named backref handling */        /* Come here from named backref handling when the reference is to a
        if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;        single group (i.e. not to a duplicated name. */
 
         HANDLE_REFERENCE:
         if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
         previous = code;          previous = code;
         *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;          *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
         PUT2INC(code, 0, recno);          PUT2INC(code, 0, recno);
Line 6535  for (;; ptr++) Line 7756  for (;; ptr++)
       /* So are Unicode property matches, if supported. */        /* So are Unicode property matches, if supported. */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
      else if (-c == ESC_P || -c == ESC_p)      else if (escape == ESC_P || escape == ESC_p)
         {          {
         BOOL negated;          BOOL negated;
        int pdata;        unsigned int ptype = 0, pdata = 0;
        int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);        if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
        if (ptype < 0) goto FAILED;          goto FAILED;
         previous = code;          previous = code;
        *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP;        *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
         *code++ = ptype;          *code++ = ptype;
         *code++ = pdata;          *code++ = pdata;
         }          }
Line 6551  for (;; ptr++) Line 7772  for (;; ptr++)
       /* If Unicode properties are not supported, \X, \P, and \p are not        /* If Unicode properties are not supported, \X, \P, and \p are not
       allowed. */        allowed. */
   
      else if (-c == ESC_X || -c == ESC_P || -c == ESC_p)      else if (escape == ESC_X || escape == ESC_P || escape == ESC_p)
         {          {
         *errorcodeptr = ERR45;          *errorcodeptr = ERR45;
         goto FAILED;          goto FAILED;
Line 6561  for (;; ptr++) Line 7782  for (;; ptr++)
       /* For the rest (including \X when Unicode properties are supported), we        /* For the rest (including \X when Unicode properties are supported), we
       can obtain the OP value by negating the escape value in the default        can obtain the OP value by negating the escape value in the default
       situation when PCRE_UCP is not set. When it *is* set, we substitute        situation when PCRE_UCP is not set. When it *is* set, we substitute
      Unicode property tests. */      Unicode property tests. Note that \b and \B do a one-character
       lookbehind, and \A also behaves as if it does. */
   
       else        else
         {          {
           if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) &&
                cd->max_lookbehind == 0)
             cd->max_lookbehind = 1;
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
        if (-c >= ESC_DU && -c <= ESC_wu)        if (escape >= ESC_DU && escape <= ESC_wu)
           {            {
           nestptr = ptr + 1;                   /* Where to resume */            nestptr = ptr + 1;                   /* Where to resume */
          ptr = substitutes[-c - ESC_DU] - 1;  /* Just before substitute */          ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
           }            }
         else          else
 #endif  #endif
Line 6577  for (;; ptr++) Line 7802  for (;; ptr++)
         so that it works in DFA mode and in lookbehinds. */          so that it works in DFA mode and in lookbehinds. */
   
           {            {
          previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;          previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
          *code++ = (!utf8 && c == -ESC_C)? OP_ALLANY : -c;          *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
           }            }
         }          }
       continue;        continue;
Line 6588  for (;; ptr++) Line 7813  for (;; ptr++)
     a value > 127. We set its representation in the length/buffer, and then      a value > 127. We set its representation in the length/buffer, and then
     handle it as a data character. */      handle it as a data character. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
    if (utf8 && c > 127)    if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
      mclength = _pcre_ord2utf8(c, mcbuffer);      mclength = PRIV(ord2utf)(c, mcbuffer);
     else      else
 #endif  #endif
   
Line 6603  for (;; ptr++) Line 7828  for (;; ptr++)
   
     /* ===================================================================*/      /* ===================================================================*/
     /* Handle a literal character. It is guaranteed not to be whitespace or #      /* Handle a literal character. It is guaranteed not to be whitespace or #
    when the extended flag is set. If we are in UTF-8 mode, it may be a    when the extended flag is set. If we are in a UTF mode, it may be a
    multi-byte literal character. */    multi-unit literal character. */
   
     default:      default:
     NORMAL_CHAR:      NORMAL_CHAR:
     mclength = 1;      mclength = 1;
     mcbuffer[0] = c;      mcbuffer[0] = c;
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
    if (utf8 && c >= 0xc0)    if (utf && HAS_EXTRALEN(c))
      {      ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr));
      while ((ptr[1] & 0xc0) == 0x80) 
        mcbuffer[mclength++] = *(++ptr); 
      } 
 #endif  #endif
   
     /* At this point we have the character's bytes in mcbuffer, and the length      /* At this point we have the character's bytes in mcbuffer, and the length
Line 6624  for (;; ptr++) Line 7846  for (;; ptr++)
   
     ONE_CHAR:      ONE_CHAR:
     previous = code;      previous = code;
   
       /* For caseless UTF-8 mode when UCP support is available, check whether
       this character has more than one other case. If so, generate a special
       OP_PROP item instead of OP_CHARI. */
   
   #ifdef SUPPORT_UCP
       if (utf && (options & PCRE_CASELESS) != 0)
         {
         GETCHAR(c, mcbuffer);
         if ((c = UCD_CASESET(c)) != 0)
           {
           *code++ = OP_PROP;
           *code++ = PT_CLIST;
           *code++ = c;
           if (firstcharflags == REQ_UNSET)
             firstcharflags = zerofirstcharflags = REQ_NONE;
           break;
           }
         }
   #endif
   
       /* Caseful matches, or not one of the multicase characters. */
   
     *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR;      *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR;
     for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];      for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];
   
Line 6634  for (;; ptr++) Line 7879  for (;; ptr++)
   
     /* Set the first and required bytes appropriately. If no previous first      /* Set the first and required bytes appropriately. If no previous first
     byte, set it from this character, but revert to none on a zero repeat.      byte, set it from this character, but revert to none on a zero repeat.
    Otherwise, leave the firstbyte value alone, and don't change it on a zero    Otherwise, leave the firstchar value alone, and don't change it on a zero
     repeat. */      repeat. */
   
    if (firstbyte == REQ_UNSET)    if (firstcharflags == REQ_UNSET)
       {        {
      zerofirstbyte = REQ_NONE;      zerofirstcharflags = REQ_NONE;
      zeroreqbyte = reqbyte;      zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
   
      /* If the character is more than one byte long, we can set firstbyte      /* If the character is more than one byte long, we can set firstchar
       only if it is not to be matched caselessly. */        only if it is not to be matched caselessly. */
   
       if (mclength == 1 || req_caseopt == 0)        if (mclength == 1 || req_caseopt == 0)
         {          {
        firstbyte = mcbuffer[0] | req_caseopt;        firstchar = mcbuffer[0] | req_caseopt;
        if (mclength != 1) reqbyte = code[-1] | cd->req_varyopt;        firstchar = mcbuffer[0];
         firstcharflags = req_caseopt;
 
         if (mclength != 1)
           {
           reqchar = code[-1];
           reqcharflags = cd->req_varyopt;
           }
         }          }
      else firstbyte = reqbyte = REQ_NONE;      else firstcharflags = reqcharflags = REQ_NONE;
       }        }
   
    /* firstbyte was previously set; we can set reqbyte only if the length is    /* firstchar was previously set; we can set reqchar only if the length is
     1 or the matching is caseful. */      1 or the matching is caseful. */
   
     else      else
       {        {
      zerofirstbyte = firstbyte;      zerofirstchar = firstchar;
      zeroreqbyte = reqbyte;      zerofirstcharflags = firstcharflags;
       zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
       if (mclength == 1 || req_caseopt == 0)        if (mclength == 1 || req_caseopt == 0)
        reqbyte = code[-1] | req_caseopt | cd->req_varyopt;        {
         reqchar = code[-1];
         reqcharflags = req_caseopt | cd->req_varyopt;
         }
       }        }
   
     break;            /* End of literal character handling */      break;            /* End of literal character handling */
Line 6680  return FALSE; Line 7938  return FALSE;
   
   
   
   
 /*************************************************  /*************************************************
 *     Compile sequence of alternatives           *  *     Compile sequence of alternatives           *
 *************************************************/  *************************************************/
Line 6693  out the amount of memory needed, as well as during the Line 7950  out the amount of memory needed, as well as during the
 value of lengthptr distinguishes the two phases.  value of lengthptr distinguishes the two phases.
   
 Arguments:  Arguments:
  options        option bits, including any changes for this subpattern  options           option bits, including any changes for this subpattern
  codeptr        -> the address of the current code pointer  codeptr           -> the address of the current code pointer
  ptrptr         -> the address of the current pattern pointer  ptrptr            -> the address of the current pattern pointer
  errorcodeptr   -> pointer to error code variable  errorcodeptr      -> pointer to error code variable
  lookbehind     TRUE if this is a lookbehind assertion  lookbehind        TRUE if this is a lookbehind assertion
  reset_bracount TRUE to reset the count for each branch  reset_bracount    TRUE to reset the count for each branch
  skipbytes      skip this many bytes at start (for brackets and OP_COND)  skipbytes         skip this many bytes at start (for brackets and OP_COND)
  cond_depth     depth of nesting for conditional subpatterns  cond_depth        depth of nesting for conditional subpatterns
  firstbyteptr   place to put the first required character, or a negative number  firstcharptr      place to put the first required character
  reqbyteptr     place to put the last required character, or a negative number  firstcharflagsptr place to put the first character flags, or a negative number
  bcptr          pointer to the chain of currently open branches  reqcharptr        place to put the last required character
  cd             points to the data block with tables pointers etc.  reqcharflagsptr   place to put the last required character flags, or a negative number
  lengthptr      NULL during the real compile phase  bcptr             pointer to the chain of currently open branches
                 points to length accumulator during pre-compile phase  cd                points to the data block with tables pointers etc.
   lengthptr         NULL during the real compile phase
                     points to length accumulator during pre-compile phase
   
Returns:         TRUE on successReturns:            TRUE on success
 */  */
   
 static BOOL  static BOOL
compile_regex(int options, uschar **codeptr, const uschar **ptrptr,compile_regex(int options, pcre_uchar **codeptr, const pcre_uchar **ptrptr,
   int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes,    int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes,
  int cond_depth, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr,  int cond_depth,
  compile_data *cd, int *lengthptr)  pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
   pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
   branch_chain *bcptr, compile_data *cd, int *lengthptr)
 {  {
const uschar *ptr = *ptrptr;const pcre_uchar *ptr = *ptrptr;
uschar *code = *codeptr;pcre_uchar *code = *codeptr;
uschar *last_branch = code;pcre_uchar *last_branch = code;
uschar *start_bracket = code;pcre_uchar *start_bracket = code;
uschar *reverse_count = NULL;pcre_uchar *reverse_count = NULL;
 open_capitem capitem;  open_capitem capitem;
 int capnumber = 0;  int capnumber = 0;
int firstbyte, reqbyte;pcre_uint32 firstchar, reqchar;
int branchfirstbyte, branchreqbyte;pcre_int32 firstcharflags, reqcharflags;
 pcre_uint32 branchfirstchar, branchreqchar;
 pcre_int32 branchfirstcharflags, branchreqcharflags;
 int length;  int length;
int orig_bracount;unsigned int orig_bracount;
int max_bracount;unsigned int max_bracount;
 branch_chain bc;  branch_chain bc;
   
 bc.outer = bcptr;  bc.outer = bcptr;
 bc.current_branch = code;  bc.current_branch = code;
   
firstbyte = reqbyte = REQ_UNSET;firstchar = reqchar = 0;
 firstcharflags = reqcharflags = REQ_UNSET;
   
 /* Accumulate the length for use in the pre-compile phase. Start with the  /* Accumulate the length for use in the pre-compile phase. Start with the
 length of the BRA and KET and any extra bytes that are required at the  length of the BRA and KET and any extra bytes that are required at the
Line 6793  for (;;) Line 8057  for (;;)
   /* Now compile the branch; in the pre-compile phase its length gets added    /* Now compile the branch; in the pre-compile phase its length gets added
   into the length. */    into the length. */
   
  if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstbyte,  if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar,
        &branchreqbyte, &bc, cond_depth, cd,        &branchfirstcharflags, &branchreqchar, &branchreqcharflags, &bc,
        (lengthptr == NULL)? NULL : &length))        cond_depth, cd, (lengthptr == NULL)? NULL : &length))
     {      {
     *ptrptr = ptr;      *ptrptr = ptr;
     return FALSE;      return FALSE;
Line 6810  for (;;) Line 8074  for (;;)
   
   if (lengthptr == NULL)    if (lengthptr == NULL)
     {      {
    /* If this is the first branch, the firstbyte and reqbyte values for the    /* If this is the first branch, the firstchar and reqchar values for the
     branch become the values for the regex. */      branch become the values for the regex. */
   
     if (*last_branch != OP_ALT)      if (*last_branch != OP_ALT)
       {        {
      firstbyte = branchfirstbyte;      firstchar = branchfirstchar;
      reqbyte = branchreqbyte;      firstcharflags = branchfirstcharflags;
       reqchar = branchreqchar;
       reqcharflags = branchreqcharflags;
       }        }
   
    /* If this is not the first branch, the first char and reqbyte have to    /* If this is not the first branch, the first char and reqchar have to
     match the values from all the previous branches, except that if the      match the values from all the previous branches, except that if the
    previous value for reqbyte didn't have REQ_VARY set, it can still match,    previous value for reqchar didn't have REQ_VARY set, it can still match,
     and we set REQ_VARY for the regex. */      and we set REQ_VARY for the regex. */
   
     else      else
       {        {
      /* If we previously had a firstbyte, but it doesn't match the new branch,      /* If we previously had a firstchar, but it doesn't match the new branch,
      we have to abandon the firstbyte for the regex, but if there was      we have to abandon the firstchar for the regex, but if there was
      previously no reqbyte, it takes on the value of the old firstbyte. */      previously no reqchar, it takes on the value of the old firstchar. */
   
      if (firstbyte >= 0 && firstbyte != branchfirstbyte)      if (firstcharflags >= 0 &&
           (firstcharflags != branchfirstcharflags || firstchar != branchfirstchar))
         {          {
        if (reqbyte < 0) reqbyte = firstbyte;        if (reqcharflags < 0)
        firstbyte = REQ_NONE;          {
           reqchar = firstchar;
           reqcharflags = firstcharflags;
           }
         firstcharflags = REQ_NONE;
         }          }
   
      /* If we (now or from before) have no firstbyte, a firstbyte from the      /* If we (now or from before) have no firstchar, a firstchar from the
      branch becomes a reqbyte if there isn't a branch reqbyte. */      branch becomes a reqchar if there isn't a branch reqchar. */
   
      if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0)      if (firstcharflags < 0 && branchfirstcharflags >= 0 && branchreqcharflags < 0)
          branchreqbyte = branchfirstbyte;        {
         branchreqchar = branchfirstchar;
         branchreqcharflags = branchfirstcharflags;
         }
   
      /* Now ensure that the reqbytes match */      /* Now ensure that the reqchars match */
   
      if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))      if (((reqcharflags & ~REQ_VARY) != (branchreqcharflags & ~REQ_VARY)) ||
        reqbyte = REQ_NONE;          reqchar != branchreqchar)
      else reqbyte |= branchreqbyte;   /* To "or" REQ_VARY */        reqcharflags = REQ_NONE;
       else
         {
         reqchar = branchreqchar;
         reqcharflags |= branchreqcharflags; /* To "or" REQ_VARY */
         }
       }        }
   
     /* If lookbehind, check that this branch matches a fixed-length string, and      /* If lookbehind, check that this branch matches a fixed-length string, and
Line 6875  for (;;) Line 8154  for (;;)
         *ptrptr = ptr;          *ptrptr = ptr;
         return FALSE;          return FALSE;
         }          }
      else { PUT(reverse_count, 0, fixed_length); }      else
         {
         if (fixed_length > cd->max_lookbehind)
           cd->max_lookbehind = fixed_length;
         PUT(reverse_count, 0, fixed_length);
         }
       }        }
     }      }
   
Line 6916  for (;;) Line 8200  for (;;)
       if (cd->open_caps->flag)        if (cd->open_caps->flag)
         {          {
         memmove(start_bracket + 1 + LINK_SIZE, start_bracket,          memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
          code - start_bracket);          IN_UCHARS(code - start_bracket));
         *start_bracket = OP_ONCE;          *start_bracket = OP_ONCE;
         code += 1 + LINK_SIZE;          code += 1 + LINK_SIZE;
         PUT(start_bracket, 1, (int)(code - start_bracket));          PUT(start_bracket, 1, (int)(code - start_bracket));
Line 6936  for (;;) Line 8220  for (;;)
   
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
    *firstbyteptr = firstbyte;    *firstcharptr = firstchar;
    *reqbyteptr = reqbyte;    *firstcharflagsptr = firstcharflags;
     *reqcharptr = reqchar;
     *reqcharflagsptr = reqcharflags;
     if (lengthptr != NULL)      if (lengthptr != NULL)
       {        {
       if (OFLOW_MAX - *lengthptr < length)        if (OFLOW_MAX - *lengthptr < length)
Line 7007  and the highest back reference was greater than or equ Line 8293  and the highest back reference was greater than or equ
 However, by keeping a bitmap of the first 31 back references, we can catch some  However, by keeping a bitmap of the first 31 back references, we can catch some
 of the more common cases more precisely.  of the more common cases more precisely.
   
   ... A second exception is when the .* appears inside an atomic group, because
   this prevents the number of characters it matches from being adjusted.
   
 Arguments:  Arguments:
   code           points to start of expression (the bracket)    code           points to start of expression (the bracket)
   bracket_map    a bitmap of which brackets we are inside while testing; this    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                    handles up to substring 31; after that we just have to take
                   the less precise approach                    the less precise approach
  backref_map    the back reference bitmap  cd             points to the compile data block
   atomcount      atomic group level
   
 Returns:     TRUE or FALSE  Returns:     TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
is_anchored(register const uschar *code, unsigned int bracket_map,is_anchored(register const pcre_uchar *code, unsigned int bracket_map,
  unsigned int backref_map)  compile_data *cd, int atomcount)
 {  {
 do {  do {
   const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code],   const pcre_uchar *scode = first_significant_code(
     FALSE);     code + PRIV(OP_lengths)[*code], FALSE);
    register int op = *scode;     register int op = *scode;
   
    /* Non-capturing brackets */     /* Non-capturing brackets */
Line 7031  do { Line 8321  do {
    if (op == OP_BRA  || op == OP_BRAPOS ||     if (op == OP_BRA  || op == OP_BRAPOS ||
        op == OP_SBRA || op == OP_SBRAPOS)         op == OP_SBRA || op == OP_SBRAPOS)
      {       {
     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;     if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
    /* Capturing brackets */     /* Capturing brackets */
Line 7041  do { Line 8331  do {
      {       {
      int n = GET2(scode, 1+LINK_SIZE);       int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);       int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
     if (!is_anchored(scode, new_map, backref_map)) return FALSE;     if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE;
      }       }
   
   /* Other brackets */   /* Positive forward assertions and conditions */
   
   else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC ||   else if (op == OP_ASSERT || op == OP_COND)
            op == OP_COND) 
      {       {
     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;     if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
      /* Atomic groups */
   
      else if (op == OP_ONCE || op == OP_ONCE_NC)
        {
        if (!is_anchored(scode, bracket_map, cd, atomcount + 1))
          return FALSE;
        }
   
    /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and     /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
   it isn't in brackets that are or may be referenced. */   it isn't in brackets that are or may be referenced or inside an atomic
    group. */
   
    else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||     else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||
              op == OP_TYPEPOSSTAR))               op == OP_TYPEPOSSTAR))
      {       {
     if (scode[1] != OP_ALLANY || (bracket_map & backref_map) != 0)     if (scode[1] != OP_ALLANY || (bracket_map & cd->backref_map) != 0 ||
          atomcount > 0 || cd->had_pruneorskip)
        return FALSE;         return FALSE;
      }       }
   
    /* Check for explicit anchoring */     /* Check for explicit anchoring */
   
    else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;     else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;
   
    code += GET(code, 1);     code += GET(code, 1);
    }     }
 while (*code == OP_ALT);   /* Loop for each alternative */  while (*code == OP_ALT);   /* Loop for each alternative */
Line 7082  return TRUE; Line 8382  return TRUE;
 matching and for non-DOTALL patterns that start with .* (which must start at  matching and for non-DOTALL patterns that start with .* (which must start at
 the beginning or after \n). As in the case of is_anchored() (see above), we  the beginning or after \n). As in the case of is_anchored() (see above), we
 have to take account of back references to capturing brackets that contain .*  have to take account of back references to capturing brackets that contain .*
because in that case we can't make the assumption.because in that case we can't make the assumption. Also, the appearance of .*
 inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not
 count, because once again the assumption no longer holds.
   
 Arguments:  Arguments:
   code           points to start of expression (the bracket)    code           points to start of expression (the bracket)
   bracket_map    a bitmap of which brackets we are inside while testing; this    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                    handles up to substring 31; after that we just have to take
                   the less precise approach                    the less precise approach
  backref_map    the back reference bitmap  cd             points to the compile data
   atomcount      atomic group level
   
 Returns:         TRUE or FALSE  Returns:         TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
is_startline(const uschar *code, unsigned int bracket_map,is_startline(const pcre_uchar *code, unsigned int bracket_map,
  unsigned int backref_map)  compile_data *cd, int atomcount)
 {  {
 do {  do {
   const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code],   const pcre_uchar *scode = first_significant_code(
     FALSE);     code + PRIV(OP_lengths)[*code], FALSE);
    register int op = *scode;     register int op = *scode;
   
    /* If we are at the start of a conditional assertion group, *both* the     /* If we are at the start of a conditional assertion group, *both* the
Line 7111  do { Line 8414  do {
    if (op == OP_COND)     if (op == OP_COND)
      {       {
      scode += 1 + LINK_SIZE;       scode += 1 + LINK_SIZE;
     if (*scode == OP_CALLOUT) scode += _pcre_OP_lengths[OP_CALLOUT];     if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT];
      switch (*scode)       switch (*scode)
        {         {
        case OP_CREF:         case OP_CREF:
       case OP_NCREF:       case OP_DNCREF:
        case OP_RREF:         case OP_RREF:
       case OP_NRREF:       case OP_DNRREF:
        case OP_DEF:         case OP_DEF:
        return FALSE;         return FALSE;
   
        default:     /* Assertion */         default:     /* Assertion */
       if (!is_startline(scode, bracket_map, backref_map)) return FALSE;       if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
        do scode += GET(scode, 1); while (*scode == OP_ALT);         do scode += GET(scode, 1); while (*scode == OP_ALT);
        scode += 1 + LINK_SIZE;         scode += 1 + LINK_SIZE;
        break;         break;
Line 7136  do { Line 8439  do {
    if (op == OP_BRA  || op == OP_BRAPOS ||     if (op == OP_BRA  || op == OP_BRAPOS ||
        op == OP_SBRA || op == OP_SBRAPOS)         op == OP_SBRA || op == OP_SBRAPOS)
      {       {
     if (!is_startline(scode, bracket_map, backref_map)) return FALSE;     if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
    /* Capturing brackets */     /* Capturing brackets */
Line 7146  do { Line 8449  do {
      {       {
      int n = GET2(scode, 1+LINK_SIZE);       int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);       int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
     if (!is_startline(scode, new_map, backref_map)) return FALSE;     if (!is_startline(scode, new_map, cd, atomcount)) return FALSE;
      }       }
   
   /* Other brackets */   /* Positive forward assertions */
   
   else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC)   else if (op == OP_ASSERT)
      {       {
     if (!is_startline(scode, bracket_map, backref_map)) return FALSE;     if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
   /* .* means "start at start or after \n" if it isn't in brackets that   /* Atomic brackets */
   may be referenced. */ 
   
      else if (op == OP_ONCE || op == OP_ONCE_NC)
        {
        if (!is_startline(scode, bracket_map, cd, atomcount + 1)) return FALSE;
        }
   
      /* .* means "start at start or after \n" if it isn't in atomic brackets or
      brackets that may be referenced, as long as the pattern does not contain
      *PRUNE or *SKIP, because these break the feature. Consider, for example,
      /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the
      start of a line. */
   
    else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)     else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
      {       {
     if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;     if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 ||
          atomcount > 0 || cd->had_pruneorskip)
        return FALSE;
      }       }
   
   /* Check for explicit circumflex */   /* Check for explicit circumflex; anything else gives a FALSE result. Note
    in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC
    because the number of characters matched by .* cannot be adjusted inside
    them. */
   
    else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;     else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;
   
Line 7186  return TRUE; Line 8504  return TRUE;
 discarded, because they can cause conflicts with actual literals that follow.  discarded, because they can cause conflicts with actual literals that follow.
 However, if we end up without a first char setting for an unanchored pattern,  However, if we end up without a first char setting for an unanchored pattern,
 it is worth scanning the regex to see if there is an initial asserted first  it is worth scanning the regex to see if there is an initial asserted first
char. If all branches start with the same asserted char, or with a bracket allchar. If all branches start with the same asserted char, or with a
of whose alternatives start with the same asserted char (recurse ad lib), thennon-conditional bracket all of whose alternatives start with the same asserted
we return that char, otherwise -1.char (recurse ad lib), then we return that char, with the flags set to zero or
 REQ_CASELESS; otherwise return zero with REQ_NONE in the flags.
   
 Arguments:  Arguments:
   code       points to start of expression (the bracket)    code       points to start of expression (the bracket)
     flags      points to the first char flags, or to REQ_NONE
   inassert   TRUE if in an assertion    inassert   TRUE if in an assertion
   
Returns:     -1 or the fixed first charReturns:     the fixed first char, or 0 with REQ_NONE in flags
 */  */
   
static intstatic pcre_uint32
find_firstassertedchar(const uschar *code, BOOL inassert)find_firstassertedchar(const pcre_uchar *code, pcre_int32 *flags,
   BOOL inassert)
 {  {
register int c = -1;register pcre_uint32 c = 0;
 int cflags = REQ_NONE;
 
 *flags = REQ_NONE;
 do {  do {
   int d;   pcre_uint32 d;
    int dflags;
    int xl = (*code == OP_CBRA || *code == OP_SCBRA ||     int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
             *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? 2:0;             *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
   const uschar *scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);   const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl,
   register int op = *scode;     TRUE);
    register pcre_uchar op = *scode;
   
    switch(op)     switch(op)
      {       {
      default:       default:
     return -1;     return 0;
   
      case OP_BRA:       case OP_BRA:
      case OP_BRAPOS:       case OP_BRAPOS:
Line 7222  do { Line 8548  do {
      case OP_ASSERT:       case OP_ASSERT:
      case OP_ONCE:       case OP_ONCE:
      case OP_ONCE_NC:       case OP_ONCE_NC:
     case OP_COND:     d = find_firstassertedchar(scode, &dflags, op == OP_ASSERT);
     if ((d = find_firstassertedchar(scode, op == OP_ASSERT)) < 0)     if (dflags < 0)
       return -1;       return 0;
     if (c < 0) c = d; else if (c != d) return -1;     if (cflags < 0) { c = d; cflags = dflags; } else if (c != d || cflags != dflags) return 0;
      break;       break;
   
      case OP_EXACT:       case OP_EXACT:
     scode += 2;     scode += IMM2_SIZE;
      /* Fall through */       /* Fall through */
   
      case OP_CHAR:       case OP_CHAR:
      case OP_PLUS:       case OP_PLUS:
      case OP_MINPLUS:       case OP_MINPLUS:
      case OP_POSPLUS:       case OP_POSPLUS:
     if (!inassert) return -1;     if (!inassert) return 0;
     if (c < 0) c = scode[1];     if (cflags < 0) { c = scode[1]; cflags = 0; }
       else if (c != scode[1]) return -1;       else if (c != scode[1]) return 0;
      break;       break;
   
      case OP_EXACTI:       case OP_EXACTI:
     scode += 2;     scode += IMM2_SIZE;
      /* Fall through */       /* Fall through */
   
      case OP_CHARI:       case OP_CHARI:
      case OP_PLUSI:       case OP_PLUSI:
      case OP_MINPLUSI:       case OP_MINPLUSI:
      case OP_POSPLUSI:       case OP_POSPLUSI:
     if (!inassert) return -1;     if (!inassert) return 0;
     if (c < 0) c = scode[1] | REQ_CASELESS;     if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; }
       else if (c != scode[1]) return -1;       else if (c != scode[1]) return 0;
      break;       break;
      }       }
   
    code += GET(code, 1);     code += GET(code, 1);
    }     }
 while (*code == OP_ALT);  while (*code == OP_ALT);
   
   *flags = cflags;
 return c;  return c;
 }  }
   
   
   
 /*************************************************  /*************************************************
   *     Add an entry to the name/number table      *
   *************************************************/
   
   /* This function is called between compiling passes to add an entry to the
   name/number table, maintaining alphabetical order. Checking for permitted
   and forbidden duplicates has already been done.
   
   Arguments:
     cd           the compile data block
     name         the name to add
     length       the length of the name
     groupno      the group number
   
   Returns:       nothing
   */
   
   static void
   add_name(compile_data *cd, const pcre_uchar *name, int length,
     unsigned int groupno)
   {
   int i;
   pcre_uchar *slot = cd->name_table;
   
   for (i = 0; i < cd->names_found; i++)
     {
     int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(length));
     if (crc == 0 && slot[IMM2_SIZE+length] != 0)
       crc = -1; /* Current name is a substring */
   
     /* Make space in the table and break the loop for an earlier name. For a
     duplicate or later name, carry on. We do this for duplicates so that in the
     simple case (when ?(| is not used) they are in order of their numbers. In all
     cases they are in the order in which they appear in the pattern. */
   
     if (crc < 0)
       {
       memmove(slot + cd->name_entry_size, slot,
         IN_UCHARS((cd->names_found - i) * cd->name_entry_size));
       break;
       }
   
     /* Continue the loop for a later or duplicate name */
   
     slot += cd->name_entry_size;
     }
   
   PUT2(slot, 0, groupno);
   memcpy(slot + IMM2_SIZE, name, IN_UCHARS(length));
   slot[IMM2_SIZE + length] = 0;
   cd->names_found++;
   }
   
   
   
   /*************************************************
 *        Compile a Regular Expression            *  *        Compile a Regular Expression            *
 *************************************************/  *************************************************/
   
Line 7285  Returns:        pointer to compiled data block, or NUL Line 8668  Returns:        pointer to compiled data block, or NUL
                 with errorptr and erroroffset set                  with errorptr and erroroffset set
 */  */
   
   #if defined COMPILE_PCRE8
 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
 pcre_compile(const char *pattern, int options, const char **errorptr,  pcre_compile(const char *pattern, int options, const char **errorptr,
   int *erroroffset, const unsigned char *tables)    int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE16
   PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
   pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr,
     int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE32
   PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
   pcre32_compile(PCRE_SPTR32 pattern, int options, const char **errorptr,
     int *erroroffset, const unsigned char *tables)
   #endif
 {  {
   #if defined COMPILE_PCRE8
 return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);  return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #elif defined COMPILE_PCRE16
   return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #elif defined COMPILE_PCRE32
   return pcre32_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #endif
 }  }
   
   
   #if defined COMPILE_PCRE8
 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
 pcre_compile2(const char *pattern, int options, int *errorcodeptr,  pcre_compile2(const char *pattern, int options, int *errorcodeptr,
   const char **errorptr, int *erroroffset, const unsigned char *tables)    const char **errorptr, int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE16
   PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
   pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr,
     const char **errorptr, int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE32
   PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
   pcre32_compile2(PCRE_SPTR32 pattern, int options, int *errorcodeptr,
     const char **errorptr, int *erroroffset, const unsigned char *tables)
   #endif
 {  {
real_pcre *re;REAL_PCRE *re;
 int length = 1;  /* For final END opcode */  int length = 1;  /* For final END opcode */
int firstbyte, reqbyte, newline;pcre_int32 firstcharflags, reqcharflags;
 pcre_uint32 firstchar, reqchar;
 pcre_uint32 limit_match = PCRE_UINT32_MAX;
 pcre_uint32 limit_recursion = PCRE_UINT32_MAX;
 int newline;
 int errorcode = 0;  int errorcode = 0;
 int skipatstart = 0;  int skipatstart = 0;
BOOL utf8;BOOL utf;
 BOOL never_utf = FALSE;
 size_t size;  size_t size;
uschar *code;pcre_uchar *code;
const uschar *codestart;const pcre_uchar *codestart;
const uschar *ptr;const pcre_uchar *ptr;
 compile_data compile_block;  compile_data compile_block;
 compile_data *cd = &compile_block;  compile_data *cd = &compile_block;
   
Line 7317  this purpose. The same space is used in the second pha Line 8731  this purpose. The same space is used in the second pha
 to fill in forward references to subpatterns. That may overflow, in which case  to fill in forward references to subpatterns. That may overflow, in which case
 new memory is obtained from malloc(). */  new memory is obtained from malloc(). */
   
uschar cworkspace[COMPILE_WORK_SIZE];pcre_uchar cworkspace[COMPILE_WORK_SIZE];
   
   /* This vector is used for remembering name groups during the pre-compile. In a
   similar way to cworkspace, it can be expanded using malloc() if necessary. */
   
   named_group named_groups[NAMED_GROUP_LIST_SIZE];
   
 /* Set this early so that early errors get offset 0. */  /* Set this early so that early errors get offset 0. */
   
ptr = (const uschar *)pattern;ptr = (const pcre_uchar *)pattern;
   
 /* We can't pass back an error message if errorptr is NULL; I guess the best we  /* We can't pass back an error message if errorptr is NULL; I guess the best we
 can do is just return NULL, but we can set a code value if there is a code  can do is just return NULL, but we can set a code value if there is a code
Line 7348  if (erroroffset == NULL) Line 8767  if (erroroffset == NULL)
   
 /* Set up pointers to the individual character tables */  /* Set up pointers to the individual character tables */
   
if (tables == NULL) tables = _pcre_default_tables;if (tables == NULL) tables = PRIV(default_tables);
 cd->lcc = tables + lcc_offset;  cd->lcc = tables + lcc_offset;
 cd->fcc = tables + fcc_offset;  cd->fcc = tables + fcc_offset;
 cd->cbits = tables + cbits_offset;  cd->cbits = tables + cbits_offset;
Line 7362  if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) Line 8781  if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0)
   goto PCRE_EARLY_ERROR_RETURN;    goto PCRE_EARLY_ERROR_RETURN;
   }    }
   
   /* If PCRE_NEVER_UTF is set, remember it. */
   
   if ((options & PCRE_NEVER_UTF) != 0) never_utf = TRUE;
   
 /* Check for global one-time settings at the start of the pattern, and remember  /* Check for global one-time settings at the start of the pattern, and remember
 the offset for later. */  the offset for later. */
   
   cd->external_flags = 0;   /* Initialize here for LIMIT_MATCH/RECURSION */
   
 while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
        ptr[skipatstart+1] == CHAR_ASTERISK)         ptr[skipatstart+1] == CHAR_ASTERISK)
   {    {
   int newnl = 0;    int newnl = 0;
   int newbsr = 0;    int newbsr = 0;
   
  if (strncmp((char *)(ptr+skipatstart+2), STRING_UTF8_RIGHTPAR, 5) == 0)/* For completeness and backward compatibility, (*UTFn) is supported in the
 relevant libraries, but (*UTF) is generic and always supported. Note that
 PCRE_UTF8 == PCRE_UTF16 == PCRE_UTF32. */
 
 #ifdef COMPILE_PCRE8
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF8_RIGHTPAR, 5) == 0)
     { skipatstart += 7; options |= PCRE_UTF8; continue; }      { skipatstart += 7; options |= PCRE_UTF8; continue; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_UCP_RIGHTPAR, 4) == 0)#endif
 #ifdef COMPILE_PCRE16
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF16_RIGHTPAR, 6) == 0)
     { skipatstart += 8; options |= PCRE_UTF16; continue; }
 #endif
 #ifdef COMPILE_PCRE32
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF32_RIGHTPAR, 6) == 0)
     { skipatstart += 8; options |= PCRE_UTF32; continue; }
 #endif
 
   else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 4) == 0)
     { skipatstart += 6; options |= PCRE_UTF8; continue; }
   else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UCP_RIGHTPAR, 4) == 0)
     { skipatstart += 6; options |= PCRE_UCP; continue; }      { skipatstart += 6; options |= PCRE_UCP; continue; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_NO_START_OPT_RIGHTPAR, 13) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_AUTO_POSSESS_RIGHTPAR, 16) == 0)
     { skipatstart += 18; options |= PCRE_NO_AUTO_POSSESS; continue; }
   else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_START_OPT_RIGHTPAR, 13) == 0)
     { skipatstart += 15; options |= PCRE_NO_START_OPTIMIZE; continue; }      { skipatstart += 15; options |= PCRE_NO_START_OPTIMIZE; continue; }
   
  if (strncmp((char *)(ptr+skipatstart+2), STRING_CR_RIGHTPAR, 3) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_MATCH_EQ, 12) == 0)
     {
     pcre_uint32 c = 0;
     int p = skipatstart + 14;
     while (isdigit(ptr[p]))
       {
       if (c > PCRE_UINT32_MAX / 10 - 1) break;   /* Integer overflow */
       c = c*10 + ptr[p++] - CHAR_0;
       }
     if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
     if (c < limit_match)
       {
       limit_match = c;
       cd->external_flags |= PCRE_MLSET;
       }
     skipatstart = p;
     continue;
     }
 
   else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_RECURSION_EQ, 16) == 0)
     {
     pcre_uint32 c = 0;
     int p = skipatstart + 18;
     while (isdigit(ptr[p]))
       {
       if (c > PCRE_UINT32_MAX / 10 - 1) break;   /* Integer overflow check */
       c = c*10 + ptr[p++] - CHAR_0;
       }
     if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
     if (c < limit_recursion)
       {
       limit_recursion = c;
       cd->external_flags |= PCRE_RLSET;
       }
     skipatstart = p;
     continue;
     }
 
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CR_RIGHTPAR, 3) == 0)
     { skipatstart += 5; newnl = PCRE_NEWLINE_CR; }      { skipatstart += 5; newnl = PCRE_NEWLINE_CR; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_LF_RIGHTPAR, 3)  == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3)  == 0)
     { skipatstart += 5; newnl = PCRE_NEWLINE_LF; }      { skipatstart += 5; newnl = PCRE_NEWLINE_LF; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_CRLF_RIGHTPAR, 5)  == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CRLF_RIGHTPAR, 5)  == 0)
     { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; }      { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_ANY_RIGHTPAR, 4) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANY_RIGHTPAR, 4) == 0)
     { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; }      { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_ANYCRLF_RIGHTPAR, 8) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANYCRLF_RIGHTPAR, 8) == 0)
     { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; }      { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; }
   
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_BSR_ANYCRLF_RIGHTPAR, 12) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_ANYCRLF_RIGHTPAR, 12) == 0)
     { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; }      { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; }
  else if (strncmp((char *)(ptr+skipatstart+2), STRING_BSR_UNICODE_RIGHTPAR, 12) == 0)  else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_UNICODE_RIGHTPAR, 12) == 0)
     { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; }      { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; }
   
   if (newnl != 0)    if (newnl != 0)
Line 7401  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && Line 8883  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
   else break;    else break;
   }    }
   
utf8 = (options & PCRE_UTF8) != 0;/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */
 utf = (options & PCRE_UTF8) != 0;
 if (utf && never_utf)
   {
   errorcode = ERR78;
   goto PCRE_EARLY_ERROR_RETURN2;
   }
   
/* Can't support UTF8 unless PCRE has been compiled to include the code. The/* Can't support UTF unless PCRE has been compiled to include the code. The
return of an error code from _pcre_valid_utf8() is a new feature, introduced inreturn of an error code from PRIV(valid_utf)() is a new feature, introduced in
 release 8.13. It is passed back from pcre_[dfa_]exec(), but at the moment is  release 8.13. It is passed back from pcre_[dfa_]exec(), but at the moment is
 not used here. */  not used here. */
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0 &&if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 &&
     (errorcode = _pcre_valid_utf8((USPTR)pattern, -1, erroroffset)) != 0)     (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0)
   {    {
   #if defined COMPILE_PCRE8
   errorcode = ERR44;    errorcode = ERR44;
   #elif defined COMPILE_PCRE16
     errorcode = ERR74;
   #elif defined COMPILE_PCRE32
     errorcode = ERR77;
   #endif
   goto PCRE_EARLY_ERROR_RETURN2;    goto PCRE_EARLY_ERROR_RETURN2;
   }    }
 #else  #else
if (utf8)if (utf)
   {    {
   errorcode = ERR32;    errorcode = ERR32;
   goto PCRE_EARLY_ERROR_RETURN;    goto PCRE_EARLY_ERROR_RETURN;
Line 7492  cd->backref_map = 0; Line 8986  cd->backref_map = 0;
 /* Reflect pattern for debugging output */  /* Reflect pattern for debugging output */
   
 DPRINTF(("------------------------------------------------------------------\n"));  DPRINTF(("------------------------------------------------------------------\n"));
DPRINTF(("%s\n", pattern));#ifdef PCRE_DEBUG
 print_puchar(stdout, (PCRE_PUCHAR)pattern);
 #endif
 DPRINTF(("\n"));
   
 /* Pretend to compile the pattern while actually just accumulating the length  /* Pretend to compile the pattern while actually just accumulating the length
 of memory required. This behaviour is triggered by passing a non-NULL final  of memory required. This behaviour is triggered by passing a non-NULL final
Line 7505  cd->bracount = cd->final_bracount = 0; Line 9002  cd->bracount = cd->final_bracount = 0;
 cd->names_found = 0;  cd->names_found = 0;
 cd->name_entry_size = 0;  cd->name_entry_size = 0;
 cd->name_table = NULL;  cd->name_table = NULL;
   cd->dupnames = FALSE;
   cd->namedrefcount = 0;
 cd->start_code = cworkspace;  cd->start_code = cworkspace;
 cd->hwm = cworkspace;  cd->hwm = cworkspace;
 cd->start_workspace = cworkspace;  cd->start_workspace = cworkspace;
 cd->workspace_size = COMPILE_WORK_SIZE;  cd->workspace_size = COMPILE_WORK_SIZE;
cd->start_pattern = (const uschar *)pattern;cd->named_groups = named_groups;
cd->end_pattern = (const uschar *)(pattern + strlen(pattern));cd->named_group_list_size = NAMED_GROUP_LIST_SIZE;
 cd->start_pattern = (const pcre_uchar *)pattern;
 cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern));
 cd->req_varyopt = 0;  cd->req_varyopt = 0;
   cd->parens_depth = 0;
   cd->assert_depth = 0;
   cd->max_lookbehind = 0;
 cd->external_options = options;  cd->external_options = options;
 cd->external_flags = 0;  
 cd->open_caps = NULL;  cd->open_caps = NULL;
   
 /* Now do the pre-compile. On error, errorcode will be set non-zero, so we  /* Now do the pre-compile. On error, errorcode will be set non-zero, so we
Line 7525  outside can help speed up starting point checks. */ Line 9028  outside can help speed up starting point checks. */
 ptr += skipatstart;  ptr += skipatstart;
 code = cworkspace;  code = cworkspace;
 *code = OP_BRA;  *code = OP_BRA;
   
 (void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE,  (void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE,
  FALSE, 0, 0, &firstbyte, &reqbyte, NULL, cd, &length);  FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL,
   cd, &length);
 if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;  if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;
   
 DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,  DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
  cd->hwm - cworkspace));  (int)(cd->hwm - cworkspace)));
   
 if (length > MAX_PATTERN_SIZE)  if (length > MAX_PATTERN_SIZE)
   {    {
Line 7538  if (length > MAX_PATTERN_SIZE) Line 9043  if (length > MAX_PATTERN_SIZE)
   goto PCRE_EARLY_ERROR_RETURN;    goto PCRE_EARLY_ERROR_RETURN;
   }    }
   
/* Compute the size of data block needed and get it, either from malloc or/* If there are groups with duplicate names and there are also references by
externally provided function. Integer overflow should no longer be possiblename, we must allow for the possibility of named references to duplicated
because nowadays we limit the maximum value of cd->names_found andgroups. These require an extra data item each. */
cd->name_entry_size. */ 
   
size = length + sizeof(real_pcre) + cd->names_found * cd->name_entry_size;if (cd->dupnames && cd->namedrefcount > 0)
re = (real_pcre *)(pcre_malloc)(size);  length += cd->namedrefcount * IMM2_SIZE * sizeof(pcre_uchar);
   
   /* Compute the size of the data block for storing the compiled pattern. Integer
   overflow should no longer be possible because nowadays we limit the maximum
   value of cd->names_found and cd->name_entry_size. */
   
   size = sizeof(REAL_PCRE) +
     (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar);
   
   /* Get the memory. */
   
   re = (REAL_PCRE *)(PUBL(malloc))(size);
 if (re == NULL)  if (re == NULL)
   {    {
   errorcode = ERR21;    errorcode = ERR21;
Line 7562  re->magic_number = MAGIC_NUMBER; Line 9076  re->magic_number = MAGIC_NUMBER;
 re->size = (int)size;  re->size = (int)size;
 re->options = cd->external_options;  re->options = cd->external_options;
 re->flags = cd->external_flags;  re->flags = cd->external_flags;
re->dummy1 = 0;re->limit_match = limit_match;
re->first_byte = 0;re->limit_recursion = limit_recursion;
re->req_byte = 0;re->first_char = 0;
re->name_table_offset = sizeof(real_pcre);re->req_char = 0;
 re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar);
 re->name_entry_size = cd->name_entry_size;  re->name_entry_size = cd->name_entry_size;
 re->name_count = cd->names_found;  re->name_count = cd->names_found;
 re->ref_count = 0;  re->ref_count = 0;
re->tables = (tables == _pcre_default_tables)? NULL : tables;re->tables = (tables == PRIV(default_tables))? NULL : tables;
 re->nullpad = NULL;  re->nullpad = NULL;
   #ifdef COMPILE_PCRE32
   re->dummy = 0;
   #else
   re->dummy1 = re->dummy2 = re->dummy3 = 0;
   #endif
   
 /* The starting points of the name/number translation table and of the code are  /* The starting points of the name/number translation table and of the code are
 passed around in the compile data block. The start/end pattern and initial  passed around in the compile data block. The start/end pattern and initial
Line 7580  field; this time it's used for remembering forward ref Line 9100  field; this time it's used for remembering forward ref
 */  */
   
 cd->final_bracount = cd->bracount;  /* Save for checking forward references */  cd->final_bracount = cd->bracount;  /* Save for checking forward references */
   cd->parens_depth = 0;
 cd->assert_depth = 0;  cd->assert_depth = 0;
 cd->bracount = 0;  cd->bracount = 0;
cd->names_found = 0;cd->max_lookbehind = 0;
cd->name_table = (uschar *)re + re->name_table_offset;cd->name_table = (pcre_uchar *)re + re->name_table_offset;
 codestart = cd->name_table + re->name_entry_size * re->name_count;  codestart = cd->name_table + re->name_entry_size * re->name_count;
 cd->start_code = codestart;  cd->start_code = codestart;
cd->hwm = (uschar *)(cd->start_workspace);cd->hwm = (pcre_uchar *)(cd->start_workspace);
 cd->req_varyopt = 0;  cd->req_varyopt = 0;
 cd->had_accept = FALSE;  cd->had_accept = FALSE;
   cd->had_pruneorskip = FALSE;
 cd->check_lookbehind = FALSE;  cd->check_lookbehind = FALSE;
 cd->open_caps = NULL;  cd->open_caps = NULL;
   
   /* If any named groups were found, create the name/number table from the list
   created in the first pass. */
   
   if (cd->names_found > 0)
     {
     int i = cd->names_found;
     named_group *ng = cd->named_groups;
     cd->names_found = 0;
     for (; i > 0; i--, ng++)
       add_name(cd, ng->name, ng->length, ng->number);
     if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE)
       (PUBL(free))((void *)cd->named_groups);
     }
   
 /* Set up a starting, non-extracting bracket, then compile the expression. On  /* Set up a starting, non-extracting bracket, then compile the expression. On
 error, errorcode will be set non-zero, so we don't need to look at the result  error, errorcode will be set non-zero, so we don't need to look at the result
 of the function here. */  of the function here. */
   
ptr = (const uschar *)pattern + skipatstart;ptr = (const pcre_uchar *)pattern + skipatstart;
code = (uschar *)codestart;code = (pcre_uchar *)codestart;
 *code = OP_BRA;  *code = OP_BRA;
 (void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0,  (void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0,
  &firstbyte, &reqbyte, NULL, cd, NULL);  &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, NULL);
 re->top_bracket = cd->bracount;  re->top_bracket = cd->bracount;
 re->top_backref = cd->top_backref;  re->top_backref = cd->top_backref;
re->flags = cd->external_flags;re->max_lookbehind = cd->max_lookbehind;
 re->flags = cd->external_flags | PCRE_MODE;
   
if (cd->had_accept) reqbyte = REQ_NONE;   /* Must disable after (*ACCEPT) */if (cd->had_accept)
   {
   reqchar = 0;              /* Must disable after (*ACCEPT) */
   reqcharflags = REQ_NONE;
   }
   
 /* If not reached end of pattern on success, there's an excess bracket. */  /* If not reached end of pattern on success, there's an excess bracket. */
   
if (errorcode == 0 && *ptr != 0) errorcode = ERR22;if (errorcode == 0 && *ptr != CHAR_NULL) errorcode = ERR22;
   
 /* Fill in the terminating state and check for disastrous overflow, but  /* Fill in the terminating state and check for disastrous overflow, but
 if debugging, leave the test till after things are printed out. */  if debugging, leave the test till after things are printed out. */
Line 7620  if debugging, leave the test till after things are pri Line 9161  if debugging, leave the test till after things are pri
 if (code - codestart > length) errorcode = ERR23;  if (code - codestart > length) errorcode = ERR23;
 #endif  #endif
   
   #ifdef SUPPORT_VALGRIND
   /* If the estimated length exceeds the really used length, mark the extra
   allocated memory as unaddressable, so that any out-of-bound reads can be
   detected. */
   VALGRIND_MAKE_MEM_NOACCESS(code, (length - (code - codestart)) * sizeof(pcre_uchar));
   #endif
   
 /* Fill in any forward references that are required. There may be repeated  /* Fill in any forward references that are required. There may be repeated
 references; optimize for them, as searching a large regex takes time. */  references; optimize for them, as searching a large regex takes time. */
   
 if (cd->hwm > cd->start_workspace)  if (cd->hwm > cd->start_workspace)
   {    {
   int prev_recno = -1;    int prev_recno = -1;
  const uschar *groupptr = NULL;  const pcre_uchar *groupptr = NULL;
   while (errorcode == 0 && cd->hwm > cd->start_workspace)    while (errorcode == 0 && cd->hwm > cd->start_workspace)
     {      {
     int offset, recno;      int offset, recno;
Line 7635  if (cd->hwm > cd->start_workspace) Line 9183  if (cd->hwm > cd->start_workspace)
     recno = GET(codestart, offset);      recno = GET(codestart, offset);
     if (recno != prev_recno)      if (recno != prev_recno)
       {        {
      groupptr = _pcre_find_bracket(codestart, utf8, recno);      groupptr = PRIV(find_bracket)(codestart, utf, recno);
       prev_recno = recno;        prev_recno = recno;
       }        }
     if (groupptr == NULL) errorcode = ERR53;      if (groupptr == NULL) errorcode = ERR53;
      else PUT(((uschar *)codestart), offset, (int)(groupptr - codestart));      else PUT(((pcre_uchar *)codestart), offset, (int)(groupptr - codestart));
     }      }
   }    }
   
/* If the workspace had to be expanded, free the new memory. *//* If the workspace had to be expanded, free the new memory. Set the pointer to
 NULL to indicate that forward references have been filled in. */
   
 if (cd->workspace_size > COMPILE_WORK_SIZE)  if (cd->workspace_size > COMPILE_WORK_SIZE)
  (pcre_free)((void *)cd->start_workspace);  (PUBL(free))((void *)cd->start_workspace);
 cd->start_workspace = NULL;
   
 /* Give an error if there's back reference to a non-existent capturing  /* Give an error if there's back reference to a non-existent capturing
 subpattern. */  subpattern. */
   
 if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15;  if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15;
   
   /* Unless disabled, check whether single character iterators can be
   auto-possessified. The function overwrites the appropriate opcode values. */
   
   if ((options & PCRE_NO_AUTO_POSSESS) == 0)
     auto_possessify((pcre_uchar *)codestart, utf, cd);
   
 /* If there were any lookbehind assertions that contained OP_RECURSE  /* If there were any lookbehind assertions that contained OP_RECURSE
 (recursions or subroutine calls), a flag is set for them to be checked here,  (recursions or subroutine calls), a flag is set for them to be checked here,
because they may contain forward references. Actual recursions can't be fixedbecause they may contain forward references. Actual recursions cannot be fixed
 length, but subroutine calls can. It is done like this so that those without  length, but subroutine calls can. It is done like this so that those without
 OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The  OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The
 exceptional ones forgo this. We scan the pattern to check that they are fixed  exceptional ones forgo this. We scan the pattern to check that they are fixed
Line 7663  length, and set their lengths. */ Line 9219  length, and set their lengths. */
   
 if (cd->check_lookbehind)  if (cd->check_lookbehind)
   {    {
  uschar *cc = (uschar *)codestart;  pcre_uchar *cc = (pcre_uchar *)codestart;
   
   /* Loop, searching for OP_REVERSE items, and process those that do not have    /* Loop, searching for OP_REVERSE items, and process those that do not have
   their length set. (Actually, it will also re-process any that have a length    their length set. (Actually, it will also re-process any that have a length
   of zero, but that is a pathological case, and it does no harm.) When we find    of zero, but that is a pathological case, and it does no harm.) When we find
   one, we temporarily terminate the branch it is in while we scan it. */    one, we temporarily terminate the branch it is in while we scan it. */
   
  for (cc = (uschar *)_pcre_find_bracket(codestart, utf8, -1);  for (cc = (pcre_uchar *)PRIV(find_bracket)(codestart, utf, -1);
        cc != NULL;         cc != NULL;
       cc = (uschar *)_pcre_find_bracket(cc, utf8, -1))       cc = (pcre_uchar *)PRIV(find_bracket)(cc, utf, -1))
     {      {
     if (GET(cc, 1) == 0)      if (GET(cc, 1) == 0)
       {        {
       int fixed_length;        int fixed_length;
      uschar *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);      pcre_uchar *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);
       int end_op = *be;        int end_op = *be;
       *be = OP_END;        *be = OP_END;
       fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,        fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,
Line 7690  if (cd->check_lookbehind) Line 9246  if (cd->check_lookbehind)
                     (fixed_length == -4)? ERR70 : ERR25;                      (fixed_length == -4)? ERR70 : ERR25;
         break;          break;
         }          }
         if (fixed_length > cd->max_lookbehind) cd->max_lookbehind = fixed_length;
       PUT(cc, 1, fixed_length);        PUT(cc, 1, fixed_length);
       }        }
     cc += 1 + LINK_SIZE;      cc += 1 + LINK_SIZE;
Line 7700  if (cd->check_lookbehind) Line 9257  if (cd->check_lookbehind)
   
 if (errorcode != 0)  if (errorcode != 0)
   {    {
  (pcre_free)(re);  (PUBL(free))(re);
   PCRE_EARLY_ERROR_RETURN:    PCRE_EARLY_ERROR_RETURN:
  *erroroffset = (int)(ptr - (const uschar *)pattern);  *erroroffset = (int)(ptr - (const pcre_uchar *)pattern);
   PCRE_EARLY_ERROR_RETURN2:    PCRE_EARLY_ERROR_RETURN2:
   *errorptr = find_error_text(errorcode);    *errorptr = find_error_text(errorcode);
   if (errorcodeptr != NULL) *errorcodeptr = errorcode;    if (errorcodeptr != NULL) *errorcodeptr = errorcode;
Line 7710  if (errorcode != 0) Line 9267  if (errorcode != 0)
   }    }
   
 /* If the anchored option was not passed, set the flag if we can determine that  /* If the anchored option was not passed, set the flag if we can determine that
the pattern is anchored by virtue of ^ characters or \A or anything else (suchthe pattern is anchored by virtue of ^ characters or \A or anything else, such
as starting with .* when DOTALL is set).as starting with non-atomic .* when DOTALL is set and there are no occurrences
 of *PRUNE or *SKIP.
   
 Otherwise, if we know what the first byte has to be, save it, because that  Otherwise, if we know what the first byte has to be, save it, because that
 speeds up unanchored matches no end. If not, see if we can set the  speeds up unanchored matches no end. If not, see if we can set the
 PCRE_STARTLINE flag. This is helpful for multiline matches when all branches  PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
start with ^. and also when all branches start with .* for non-DOTALL matches.start with ^. and also when all branches start with non-atomic .* for
*/non-DOTALL matches when *PRUNE and SKIP are not present. */
   
 if ((re->options & PCRE_ANCHORED) == 0)  if ((re->options & PCRE_ANCHORED) == 0)
   {    {
  if (is_anchored(codestart, 0, cd->backref_map))  if (is_anchored(codestart, 0, cd, 0)) re->options |= PCRE_ANCHORED;
    re->options |= PCRE_ANCHORED; 
   else    else
     {      {
    if (firstbyte < 0)    if (firstcharflags < 0)
      firstbyte = find_firstassertedchar(codestart, FALSE);      firstchar = find_firstassertedchar(codestart, &firstcharflags, FALSE);
    if (firstbyte >= 0)   /* Remove caseless flag for non-caseable chars */    if (firstcharflags >= 0)   /* Remove caseless flag for non-caseable chars */
       {        {
      int ch = firstbyte & 255;#if defined COMPILE_PCRE8
      re->first_byte = ((firstbyte & REQ_CASELESS) != 0 &&      re->first_char = firstchar & 0xff;
         cd->fcc[ch] == ch)? ch : firstbyte;#elif defined COMPILE_PCRE16
       re->first_char = firstchar & 0xffff;
 #elif defined COMPILE_PCRE32
       re->first_char = firstchar;
 #endif
       if ((firstcharflags & REQ_CASELESS) != 0)
         {
 #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
         /* We ignore non-ASCII first chars in 8 bit mode. */
         if (utf)
           {
           if (re->first_char < 128)
             {
             if (cd->fcc[re->first_char] != re->first_char)
               re->flags |= PCRE_FCH_CASELESS;
             }
           else if (UCD_OTHERCASE(re->first_char) != re->first_char)
             re->flags |= PCRE_FCH_CASELESS;
           }
         else
 #endif
         if (MAX_255(re->first_char)
             && cd->fcc[re->first_char] != re->first_char)
           re->flags |= PCRE_FCH_CASELESS;
         }
 
       re->flags |= PCRE_FIRSTSET;        re->flags |= PCRE_FIRSTSET;
       }        }
    else if (is_startline(codestart, 0, cd->backref_map))
      re->flags |= PCRE_STARTLINE;    else if (is_startline(codestart, 0, cd, 0)) re->flags |= PCRE_STARTLINE;
     }      }
   }    }
   
Line 7743  if ((re->options & PCRE_ANCHORED) == 0) Line 9325  if ((re->options & PCRE_ANCHORED) == 0)
 variable length item in the regex. Remove the caseless flag for non-caseable  variable length item in the regex. Remove the caseless flag for non-caseable
 bytes. */  bytes. */
   
if (reqbyte >= 0 &&if (reqcharflags >= 0 &&
     ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0))     ((re->options & PCRE_ANCHORED) == 0 || (reqcharflags & REQ_VARY) != 0))
   {    {
  int ch = reqbyte & 255;#if defined COMPILE_PCRE8
  re->req_byte = ((reqbyte & REQ_CASELESS) != 0 &&  re->req_char = reqchar & 0xff;
    cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;#elif defined COMPILE_PCRE16
   re->req_char = reqchar & 0xffff;
 #elif defined COMPILE_PCRE32
   re->req_char = reqchar;
 #endif
   if ((reqcharflags & REQ_CASELESS) != 0)
     {
 #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
     /* We ignore non-ASCII first chars in 8 bit mode. */
     if (utf)
       {
       if (re->req_char < 128)
         {
         if (cd->fcc[re->req_char] != re->req_char)
           re->flags |= PCRE_RCH_CASELESS;
         }
       else if (UCD_OTHERCASE(re->req_char) != re->req_char)
         re->flags |= PCRE_RCH_CASELESS;
       }
     else
 #endif
     if (MAX_255(re->req_char) && cd->fcc[re->req_char] != re->req_char)
       re->flags |= PCRE_RCH_CASELESS;
     }
 
   re->flags |= PCRE_REQCHSET;    re->flags |= PCRE_REQCHSET;
   }    }
   
Line 7763  printf("Options=%08x\n", re->options); Line 9369  printf("Options=%08x\n", re->options);
   
 if ((re->flags & PCRE_FIRSTSET) != 0)  if ((re->flags & PCRE_FIRSTSET) != 0)
   {    {
  int ch = re->first_byte & 255;  pcre_uchar ch = re->first_char;
  const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)?  const char *caseless =
    "" : " (caseless)";    ((re->flags & PCRE_FCH_CASELESS) == 0)? "" : " (caseless)";
  if (isprint(ch)) printf("First char = %c%s\n", ch, caseless);  if (PRINTABLE(ch)) printf("First char = %c%s\n", ch, caseless);
     else printf("First char = \\x%02x%s\n", ch, caseless);      else printf("First char = \\x%02x%s\n", ch, caseless);
   }    }
   
 if ((re->flags & PCRE_REQCHSET) != 0)  if ((re->flags & PCRE_REQCHSET) != 0)
   {    {
  int ch = re->req_byte & 255;  pcre_uchar ch = re->req_char;
  const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)?  const char *caseless =
    "" : " (caseless)";    ((re->flags & PCRE_RCH_CASELESS) == 0)? "" : " (caseless)";
  if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless);  if (PRINTABLE(ch)) printf("Req char = %c%s\n", ch, caseless);
     else printf("Req char = \\x%02x%s\n", ch, caseless);      else printf("Req char = \\x%02x%s\n", ch, caseless);
   }    }
   
pcre_printint(re, stdout, TRUE);#if defined COMPILE_PCRE8
 pcre_printint((pcre *)re, stdout, TRUE);
 #elif defined COMPILE_PCRE16
 pcre16_printint((pcre *)re, stdout, TRUE);
 #elif defined COMPILE_PCRE32
 pcre32_printint((pcre *)re, stdout, TRUE);
 #endif
   
 /* This check is done here in the debugging case so that the code that  /* This check is done here in the debugging case so that the code that
 was compiled can be seen. */  was compiled can be seen. */
   
 if (code - codestart > length)  if (code - codestart > length)
   {    {
  (pcre_free)(re);  (PUBL(free))(re);
   *errorptr = find_error_text(ERR23);    *errorptr = find_error_text(ERR23);
  *erroroffset = ptr - (uschar *)pattern;  *erroroffset = ptr - (pcre_uchar *)pattern;
   if (errorcodeptr != NULL) *errorcodeptr = ERR23;    if (errorcodeptr != NULL) *errorcodeptr = ERR23;
   return NULL;    return NULL;
   }    }
 #endif   /* PCRE_DEBUG */  #endif   /* PCRE_DEBUG */
   
   /* Check for a pattern than can match an empty string, so that this information
   can be provided to applications. */
   
   do
     {
     if (could_be_empty_branch(codestart, code, utf, cd, NULL))
       {
       re->flags |= PCRE_MATCH_EMPTY;
       break;
       }
     codestart += GET(codestart, 1);
     }
   while (*codestart == OP_ALT);
   
   #if defined COMPILE_PCRE8
 return (pcre *)re;  return (pcre *)re;
   #elif defined COMPILE_PCRE16
   return (pcre16 *)re;
   #elif defined COMPILE_PCRE32
   return (pcre32 *)re;
   #endif
 }  }
   
 /* End of pcre_compile.c */  /* End of pcre_compile.c */
   

Removed from v.1.1  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>