Diff for /embedaddon/pcre/pcre_compile.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2012/02/21 23:05:51 version 1.1.1.2, 2012/02/21 23:50:25
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-2012 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)_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
   
   
Line 104  overrun before it actually does run off the end of the Line 108  overrun before it actually does run off the end of the
   
 #define WORK_SIZE_SAFETY_MARGIN (100)  #define WORK_SIZE_SAFETY_MARGIN (100)
   
   /* Private flags added to firstchar and reqchar. */
   
   #define REQ_CASELESS   0x10000000l      /* Indicates caselessness */
   #define REQ_VARY       0x20000000l      /* Reqchar followed non-literal item */
   
   /* 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 238  static const char posix_names[] = Line 250  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 };
   
 /* 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
Line 273  substitutes must be in the order of the names, defined Line 285  substitutes must be in the order of the names, defined
 both positive and negative cases. NULL means no substitute. */  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 */       /* NOTE: Xsp is Perl space */
   string_pXsp,          /* \s */
   string_PXwd,          /* \W */
   string_pXwd           /* \w */
 };  };
   
static const uschar *posix_substitutes[] = {static const pcre_uchar string_pL[] =   {
  (uschar *)"\\p{L}",     /* alpha */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  (uschar *)"\\p{Ll}",    /* lower */  CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\p{Lu}",    /* upper */static const pcre_uchar string_pLl[] =  {
  (uschar *)"\\p{Xan}",   /* alnum */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  NULL,                   /* ascii */  CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\h",        /* blank */static const pcre_uchar string_pLu[] =  {
  NULL,                   /* cntrl */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  (uschar *)"\\p{Nd}",    /* digit */  CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  NULL,                   /* graph */static const pcre_uchar string_pXan[] = {
  NULL,                   /* print */  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
  NULL,                   /* punct */  CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
  (uschar *)"\\p{Xps}",   /* space */    /* NOTE: Xps is POSIX space */static const pcre_uchar string_h[] =    {
  (uschar *)"\\p{Xwd}",   /* word */  CHAR_BACKSLASH, CHAR_h, '\0' };
  NULL,                   /* xdigit */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 */    /* NOTE: Xps is POSIX space */
   string_pXwd,          /* word */
   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 */   /* NOTE: Xps is POSIX space */
  (uschar *)"\\P{Xwd}",   /* ^word */  string_PXwd,          /* ^word */
  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 438  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{...} sequence is too large\0"
   /* 35 */    /* 35 */
Line 395  static const char error_texts[] = Line 461  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 414  static const char error_texts[] = Line 480  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"
   ;    ;
   
 /* 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 507  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 557  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 592  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 557  static const unsigned char ebcdic_chartab[] = { /* cha Line 631  static const unsigned char ebcdic_chartab[] = { /* cha
 /* Definition to allow mutual recursion */  /* Definition to allow mutual recursion */
   
 static BOOL  static BOOL
  compile_regex(int, uschar **, const uschar **, int *, BOOL, BOOL, int, int,  compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int,
     int *, int *, branch_chain *, compile_data *, int *);      int *, int *, branch_chain *, compile_data *, int *);
   
   
Line 604  Returns:  0 if all went well, else an error number Line 678  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 686  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 715  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 684  Returns:         zero or positive => a data character Line 759  Returns:         zero or positive => a data character
 */  */
   
 static int  static int
check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount,check_escape(const pcre_uchar **ptrptr, int *errorcodeptr, int bracount,
   int options, BOOL isclass)    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_int32 c;
 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 */
Line 703  in a table. A non-zero result is something that can be Line 780  in a table. A non-zero result is something that can be
 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 (c < CHAR_0 || c > CHAR_z) {}
 else if ((i = escapes[c - CHAR_0]) != 0) c = i;  else if ((i = escapes[c - CHAR_0]) != 0) c = i;
   
 #else           /* EBCDIC coding */  #else           /* EBCDIC coding */
else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {}   /* Not alphanumeric *//* Not alphanumeric */
 else if (c < 'a' || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {}
 else if ((i = escapes[c - 0x48]) != 0)  c = i;  else if ((i = escapes[c - 0x48]) != 0)  c = i;
 #endif  #endif
   
Line 715  else if ((i = escapes[c - 0x48]) != 0)  c = i; Line 794  else if ((i = escapes[c - 0x48]) != 0)  c = i;
   
 else  else
   {    {
  const uschar *oldptr;  const pcre_uchar *oldptr;
   BOOL braced, negated;    BOOL braced, negated;
   
   switch (c)    switch (c)
Line 733  else Line 812  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)
Line 788  else Line 869  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 != 0 && *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 != 0 && *p != CHAR_RIGHT_CURLY_BRACKET)
         {          {
         c = -ESC_k;          c = -ESC_k;
Line 808  else Line 889  else
       }        }
     else negated = FALSE;      else negated = FALSE;
   
       /* The integer range is limited by the machine's int representation. */
     c = 0;      c = 0;
    while ((digitab[ptr[1]] & ctype_digit) != 0)    while (IS_DIGIT(ptr[1]))
       {
       if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */
         {
         c = -1;
         break;
         }
       c = c * 10 + *(++ptr) - CHAR_0;        c = c * 10 + *(++ptr) - CHAR_0;
      }
    if (c < 0)   /* Integer overflow */    if (((unsigned int)c) > INT_MAX) /* Integer overflow */
       {        {
         while (IS_DIGIT(ptr[1]))
           ptr++;
       *errorcodeptr = ERR61;        *errorcodeptr = ERR61;
       break;        break;
       }        }
Line 861  else Line 951  else
     if (!isclass)      if (!isclass)
       {        {
       oldptr = ptr;        oldptr = ptr;
         /* The integer range is limited by the machine's int representation. */
       c -= CHAR_0;        c -= CHAR_0;
      while ((digitab[ptr[1]] & ctype_digit) != 0)      while (IS_DIGIT(ptr[1]))
         {
         if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */
           {
           c = -1;
           break;
           }
         c = c * 10 + *(++ptr) - CHAR_0;          c = c * 10 + *(++ptr) - CHAR_0;
      if (c < 0)    /* Integer overflow */        }
       if (((unsigned int)c) > INT_MAX) /* Integer overflow */
         {          {
           while (IS_DIGIT(ptr[1]))
             ptr++;
         *errorcodeptr = ERR61;          *errorcodeptr = ERR61;
         break;          break;
         }          }
Line 891  else Line 991  else
     /* \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      /* \x is complicated. \x{ddd} is a character number which can be greater
    than 0xff in utf8 mode, but only if the ddd are hex digits. If not, { is    than 0xff in utf or non-8bit mode, but only if the ddd are hex digits.
    treated as a data character. */    If not, { is treated as a data character. */
   
     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.        /* In JavaScript, \x must be followed by two hexadecimal numbers.
       Otherwise it is a lowercase x letter. */        Otherwise it is a lowercase x 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
         && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0)
         {          {
         c = 0;          c = 0;
         for (i = 0; i < 2; ++i)          for (i = 0; i < 2; ++i)
Line 930  else Line 1033  else
   
     if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)      if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
       {        {
      const uschar *pt = ptr + 2;      const pcre_uchar *pt = ptr + 2;
      int count = 0; 
   
       c = 0;        c = 0;
      while ((digitab[*pt] & ctype_xdigit) != 0)      while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0)
         {          {
         register int cc = *pt++;          register int cc = *pt++;
         if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */          if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
         count++;  
   
 #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 */
Line 947  else Line 1048  else
         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
   
   #ifdef COMPILE_PCRE8
           if (c > (utf ? 0x10ffff : 0xff)) { c = -1; break; }
   #else
   #ifdef COMPILE_PCRE16
           if (c > (utf ? 0x10ffff : 0xffff)) { c = -1; break; }
   #endif
   #endif
         }          }
   
         if (c < 0)
           {
           while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0) pt++;
           *errorcodeptr = ERR34;
           }
   
       if (*pt == CHAR_RIGHT_CURLY_BRACKET)        if (*pt == CHAR_RIGHT_CURLY_BRACKET)
         {          {
        if (c < 0 || count > (utf8? 8 : 2)) *errorcodeptr = ERR34;        if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
         ptr = pt;          ptr = pt;
         break;          break;
         }          }
Line 963  else Line 1078  else
     /* Read just a single-byte hex-defined char */      /* Read just a single-byte hex-defined char */
   
     c = 0;      c = 0;
    while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0)    while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0)
       {        {
       int cc;                                  /* Some compilers don't like */        int cc;                                  /* Some compilers don't like */
       cc = *(++ptr);                           /* ++ in initializers */        cc = *(++ptr);                           /* ++ in initializers */
Line 1061  Returns:         type value from ucp_type_table, or -1 Line 1176  Returns:         type value from ucp_type_table, or -1
 */  */
   
 static int  static int
get_ucp(const uschar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr)get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr)
 {  {
 int c, i, bot, top;  int c, i, bot, top;
const uschar *ptr = *ptrptr;const pcre_uchar *ptr = *ptrptr;
char name[32];pcre_uchar name[32];
   
 c = *(++ptr);  c = *(++ptr);
 if (c == 0) goto ERROR_RETURN;  if (c == 0) goto ERROR_RETURN;
Line 1082  if (c == CHAR_LEFT_CURLY_BRACKET) Line 1197  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 == 0) goto ERROR_RETURN;
Line 1106  else Line 1221  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)
   {    {
   i = (bot + top) >> 1;    i = (bot + top) >> 1;
  c = strcmp(name, _pcre_utt_names + _pcre_utt[i].name_offset);  c = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
   if (c == 0)    if (c == 0)
     {      {
    *dptr = _pcre_utt[i].value;    *dptr = PRIV(utt)[i].value;
    return _pcre_utt[i].type;    return PRIV(utt)[i].type;
     }      }
   if (c > 0) bot = i + 1; else top = i;    if (c > 0) bot = i + 1; else top = i;
   }    }
Line 1153  Returns:         pointer to '}' on success; Line 1268  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 1277  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 + *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 1292  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 + *p++ - CHAR_0;
     if (max < 0 || max > 65535)      if (max < 0 || max > 65535)
       {        {
       *errorcodeptr = ERR5;        *errorcodeptr = ERR5;
Line 1232  Arguments: Line 1347  Arguments:
   name         name to seek, or NULL if seeking a numbered subpattern    name         name to seek, or NULL if seeking a numbered subpattern
   lorn         name length, or subpattern number if name is NULL    lorn         name length, or subpattern number if name is NULL
   xmode        TRUE if we are in /x mode    xmode        TRUE if we are in /x mode
  utf8         TRUE if we are in UTF-8 mode  utf          TRUE if we are in UTF-8 / UTF-16 mode
   count        pointer to the current capturing subpattern number (updated)    count        pointer to the current capturing subpattern number (updated)
   
 Returns:       the number of the named subpattern, or -1 if not found  Returns:       the number of the named subpattern, or -1 if not found
 */  */
   
 static int  static int
find_parens_sub(uschar **ptrptr, compile_data *cd, const uschar *name, int lorn,find_parens_sub(pcre_uchar **ptrptr, compile_data *cd, const pcre_uchar *name, int lorn,
  BOOL xmode, BOOL utf8, int *count)  BOOL xmode, BOOL utf, int *count)
 {  {
uschar *ptr = *ptrptr;pcre_uchar *ptr = *ptrptr;
 int start_count = *count;  int start_count = *count;
 int hwm_count = start_count;  int hwm_count = start_count;
 BOOL dup_parens = FALSE;  BOOL dup_parens = FALSE;
Line 1309  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1424  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
         ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE)          ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE)
       {        {
       int term;        int term;
      const uschar *thisname;      const pcre_uchar *thisname;
       *count += 1;        *count += 1;
       if (name == NULL && *count == lorn) return *count;        if (name == NULL && *count == lorn) return *count;
       term = *ptr++;        term = *ptr++;
Line 1317  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1432  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
       thisname = ptr;        thisname = ptr;
       while (*ptr != term) ptr++;        while (*ptr != term) ptr++;
       if (name != NULL && lorn == ptr - thisname &&        if (name != NULL && lorn == ptr - thisname &&
          strncmp((const char *)name, (const char *)thisname, lorn) == 0)          STRNCMP_UC_UC(name, thisname, lorn) == 0)
         return *count;          return *count;
       term++;        term++;
       }        }
Line 1360  for (; ptr < cd->end_pattern; ptr++) Line 1475  for (; ptr < cd->end_pattern; ptr++)
         {          {
         if (ptr[2] == CHAR_E)          if (ptr[2] == CHAR_E)
           ptr+= 2;            ptr+= 2;
        else if (strncmp((const char *)ptr+2,        else if (STRNCMP_UC_C8(ptr + 2,
                  STR_Q STR_BACKSLASH STR_E, 3) == 0)                   STR_Q STR_BACKSLASH STR_E, 3) == 0)
           ptr += 4;            ptr += 4;
         else          else
Line 1408  for (; ptr < cd->end_pattern; ptr++) Line 1523  for (; ptr < cd->end_pattern; ptr++)
       {        {
       if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }        if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; 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) goto FAIL_EXIT;      if (*ptr == 0) goto FAIL_EXIT;
Line 1420  for (; ptr < cd->end_pattern; ptr++) Line 1535  for (; ptr < cd->end_pattern; ptr++)
   
   if (*ptr == CHAR_LEFT_PARENTHESIS)    if (*ptr == CHAR_LEFT_PARENTHESIS)
     {      {
    int rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf8, count);    int rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, count);
     if (rc > 0) return rc;      if (rc > 0) return rc;
     if (*ptr == 0) goto FAIL_EXIT;      if (*ptr == 0) goto FAIL_EXIT;
     }      }
Line 1466  Arguments: Line 1581  Arguments:
   name         name to seek, or NULL if seeking a numbered subpattern    name         name to seek, or NULL if seeking a numbered subpattern
   lorn         name length, or subpattern number if name is NULL    lorn         name length, or subpattern number if name is NULL
   xmode        TRUE if we are in /x mode    xmode        TRUE if we are in /x mode
  utf8         TRUE if we are in UTF-8 mode  utf          TRUE if we are in UTF-8 / UTF-16 mode
   
 Returns:       the number of the found subpattern, or -1 if not found  Returns:       the number of the found subpattern, or -1 if not found
 */  */
   
 static int  static int
find_parens(compile_data *cd, const uschar *name, int lorn, BOOL xmode,find_parens(compile_data *cd, const pcre_uchar *name, int lorn, BOOL xmode,
  BOOL utf8)  BOOL utf)
 {  {
uschar *ptr = (uschar *)cd->start_pattern;pcre_uchar *ptr = (pcre_uchar *)cd->start_pattern;
 int count = 0;  int count = 0;
 int rc;  int rc;
   
Line 1486  matching closing parens. That is why we have to have a Line 1601  matching closing parens. That is why we have to have a
   
 for (;;)  for (;;)
   {    {
  rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf8, &count);  rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, &count);
   if (rc > 0 || *ptr++ == 0) break;    if (rc > 0 || *ptr++ == 0) break;
   }    }
   
Line 1513  Arguments: Line 1628  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 1640  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 1539  for (;;) Line 1654  for (;;)
     case OP_RREF:      case OP_RREF:
     case OP_NRREF:      case OP_NRREF:
     case OP_DEF:      case OP_DEF:
    code += _pcre_OP_lengths[*code];    code += PRIV(OP_lengths)[*code];
     break;      break;
   
     default:      default:
Line 1569  and doing the check at the end; a flag specifies which Line 1684  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 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 1696  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 1709  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 int 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 1724  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 1755  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 1771  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 1780  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 1690  for (;;) Line 1807  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 1818  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 1714  for (;;) Line 1831  for (;;)
     case OP_NOTEXACT:      case OP_NOTEXACT:
     case OP_NOTEXACTI:      case OP_NOTEXACTI:
     branchlength += GET2(cc,1);      branchlength += 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 += 2;
    cc += 4;    cc += 1 + IMM2_SIZE + 1;
     break;      break;
   
     /* Handle single-char matchers */      /* Handle single-char matchers */
Line 1757  for (;;) Line 1874  for (;;)
   
     /* Check a class for variable quantification */      /* Check a class for variable quantification */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF || defined COMPILE_PCRE16
     case OP_XCLASS:      case OP_XCLASS:
    cc += GET(cc, 1) - 33;    cc += GET(cc, 1) - PRIV(OP_lengths)[OP_CLASS];
     /* Fall through */      /* Fall through */
 #endif  #endif
   
     case OP_CLASS:      case OP_CLASS:
     case OP_NCLASS:      case OP_NCLASS:
    cc += 33;    cc += PRIV(OP_lengths)[OP_CLASS];
   
     switch (*cc)      switch (*cc)
       {        {
Line 1779  for (;;) Line 1896  for (;;)
   
       case OP_CRRANGE:        case OP_CRRANGE:
       case OP_CRMINRANGE:        case OP_CRMINRANGE:
      if (GET2(cc,1) != GET2(cc,3)) return -1;      if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1;
       branchlength += GET2(cc,1);        branchlength += GET2(cc,1);
      cc += 5;      cc += 1 + 2 * IMM2_SIZE;
       break;        break;
   
       default:        default:
Line 1896  length. Line 2013  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 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 (;;)
   {    {
Line 1921  for (;;) Line 2038  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 1931  for (;;) Line 2048  for (;;)
            c == OP_CBRAPOS || c == OP_SCBRAPOS)             c == OP_CBRAPOS || c == OP_SCBRAPOS)
     {      {
     int n = GET2(code, 1+LINK_SIZE);      int n = 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 2077  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:
Line 1976  for (;;) Line 2094  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#ifdef SUPPORT_UTF
    if (utf8) switch(c)    if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
       case OP_CHARI:        case OP_CHARI:
Line 2013  for (;;) Line 2131  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 2152  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 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 (;;)
   {    {
Line 2079  for (;;) Line 2197  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:
Line 2095  for (;;) Line 2214  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#ifdef SUPPORT_UTF
    if (utf8) switch(c)    if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
       case OP_CHARI:        case OP_CHARI:
Line 2132  for (;;) Line 2251  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 2159  bracket whose current branch will already have been sc Line 2278  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 mode
   cd          contains pointers to tables etc.    cd          contains 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_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)
 {  {
 register int c;  register int c;
for (code = first_significant_code(code + _pcre_OP_lengths[*code], TRUE);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 2316  for (code = first_significant_code(code + _pcre_OP_len
   
   if (c == OP_RECURSE)    if (c == OP_RECURSE)
     {      {
    const uschar *scode;    const pcre_uchar *scode;
     BOOL empty_branch;      BOOL empty_branch;
   
     /* Test for forward reference */      /* Test for forward reference */
Line 2215  for (code = first_significant_code(code + _pcre_OP_len Line 2334  for (code = first_significant_code(code + _pcre_OP_len
   
     do      do
       {        {
      if (could_be_empty_branch(scode, endcode, utf8, cd))      if (could_be_empty_branch(scode, endcode, utf, cd))
         {          {
         empty_branch = TRUE;          empty_branch = TRUE;
         break;          break;
Line 2233  for (code = first_significant_code(code + _pcre_OP_len Line 2352  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 2390  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))
           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 2408  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 2420  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 2376  for (code = first_significant_code(code + _pcre_OP_len Line 2495  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 2391  for (code = first_significant_code(code + _pcre_OP_len Line 2511  for (code = first_significant_code(code + _pcre_OP_len
     /* 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 may be followed by a multibyte character */
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
     case OP_STAR:      case OP_STAR:
     case OP_STARI:      case OP_STARI:
     case OP_MINSTAR:      case OP_MINSTAR:
Line 2404  for (code = first_significant_code(code + _pcre_OP_len Line 2524  for (code = first_significant_code(code + _pcre_OP_len
     case OP_MINQUERYI:      case OP_MINQUERYI:
     case OP_POSQUERY:      case OP_POSQUERY:
     case OP_POSQUERYI:      case OP_POSQUERYI:
    if (utf8 && code[1] >= 0xc0) code += _pcre_utf8_table4[code[1] & 0x3f];    if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]);
     break;      break;
   
     case OP_UPTO:      case OP_UPTO:
Line 2413  for (code = first_significant_code(code + _pcre_OP_len Line 2533  for (code = first_significant_code(code + _pcre_OP_len
     case OP_MINUPTOI:      case OP_MINUPTOI:
     case OP_POSUPTO:      case OP_POSUPTO:
     case OP_POSUPTOI:      case OP_POSUPTOI:
    if (utf8 && code[3] >= 0xc0) code += _pcre_utf8_table4[code[3] & 0x3f];    if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]);
     break;      break;
 #endif  #endif
   
Line 2457  Arguments: Line 2577  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 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))
     return FALSE;      return FALSE;
   bcptr = bcptr->outer;    bcptr = bcptr->outer;
   }    }
Line 2521  Returns:   TRUE or FALSE Line 2641  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 */  int 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. */
Line 2565  Returns:     a value representing the name, or -1 if u Line 2685  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, 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 2724  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 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 2732  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. */
Line 2665  Arguments: Line 2785  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 2814  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 2777  switch(ptype) Line 2897  switch(ptype)
           prop->chartype == ucp_Lt) == negated;            prop->chartype == ucp_Lt) == negated;
   
   case PT_GC:    case PT_GC:
  return (pdata == _pcre_ucp_gentype[prop->chartype]) == negated;  return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
   
   case PT_PC:    case PT_PC:
   return (pdata == prop->chartype) == negated;    return (pdata == prop->chartype) == negated;
Line 2788  switch(ptype) Line 2908  switch(ptype)
   /* These are specials */    /* These are specials */
   
   case PT_ALNUM:    case PT_ALNUM:
  return (_pcre_ucp_gentype[prop->chartype] == ucp_L ||  return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
          _pcre_ucp_gentype[prop->chartype] == ucp_N) == negated;          PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
   
   case PT_SPACE:    /* Perl space */    case PT_SPACE:    /* Perl space */
  return (_pcre_ucp_gentype[prop->chartype] == ucp_Z ||  return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z ||
           c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR)            c == CHAR_HT || c == CHAR_NL || c == CHAR_FF || c == CHAR_CR)
           == negated;            == negated;
   
   case PT_PXSPACE:  /* POSIX space */    case PT_PXSPACE:  /* POSIX space */
  return (_pcre_ucp_gentype[prop->chartype] == ucp_Z ||  return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z ||
           c == CHAR_HT || c == CHAR_NL || c == CHAR_VT ||            c == CHAR_HT || c == CHAR_NL || c == CHAR_VT ||
           c == CHAR_FF || c == CHAR_CR)            c == CHAR_FF || c == CHAR_CR)
           == negated;            == negated;
   
   case PT_WORD:    case PT_WORD:
  return (_pcre_ucp_gentype[prop->chartype] == ucp_L ||  return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
          _pcre_ucp_gentype[prop->chartype] == ucp_N ||          PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
           c == CHAR_UNDERSCORE) == negated;            c == CHAR_UNDERSCORE) == negated;
   }    }
 return FALSE;  return FALSE;
Line 2823  sense to automatically possessify the repeated item. Line 2943  sense to automatically possessify the repeated item.
   
 Arguments:  Arguments:
   previous      pointer to the repeated opcode    previous      pointer to the repeated opcode
  utf8          TRUE in UTF-8 mode  utf           TRUE in UTF-8 / UTF-16 mode
   ptr           next character in pattern    ptr           next character in pattern
   options       options bits    options       options bits
   cd            contains pointers to tables etc.    cd            contains pointers to tables etc.
Line 2832  Returns:        TRUE if possessifying is wanted Line 2952  Returns:        TRUE if possessifying is wanted
 */  */
   
 static BOOL  static BOOL
check_auto_possessive(const uschar *previous, BOOL utf8, const uschar *ptr,check_auto_possessive(const pcre_uchar *previous, BOOL utf,
  int options, compile_data *cd)  const pcre_uchar *ptr, int options, compile_data *cd)
 {  {
int c, next;pcre_int32 c, next;
 int op_code = *previous++;  int op_code = *previous++;
   
 /* Skip whitespace and comments in extended mode */  /* Skip whitespace and comments in extended mode */
Line 2844  if ((options & PCRE_EXTENDED) != 0) Line 2964  if ((options & PCRE_EXTENDED) != 0)
   {    {
   for (;;)    for (;;)
     {      {
    while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++;    while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_space) != 0) ptr++;
     if (*ptr == CHAR_NUMBER_SIGN)      if (*ptr == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
Line 2852  if ((options & PCRE_EXTENDED) != 0) Line 2972  if ((options & PCRE_EXTENDED) != 0)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }          if (IS_NEWLINE(ptr)) { 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
         }          }
       }        }
Line 2871  if (*ptr == CHAR_BACKSLASH) Line 2991  if (*ptr == CHAR_BACKSLASH)
   if (temperrorcode != 0) return FALSE;    if (temperrorcode != 0) return FALSE;
   ptr++;    /* Point after the escape sequence */    ptr++;    /* Point after the escape sequence */
   }    }
else if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_meta) == 0)
else if ((cd->ctypes[*ptr] & ctype_meta) == 0) 
   {    {
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
  if (utf8) { GETCHARINC(next, ptr); } else  if (utf) { GETCHARINC(next, ptr); } else
 #endif  #endif
   next = *ptr++;    next = *ptr++;
   }    }
   
 else return FALSE;  else return FALSE;
   
 /* Skip whitespace and comments in extended mode */  /* Skip whitespace and comments in extended mode */
Line 2888  if ((options & PCRE_EXTENDED) != 0) Line 3006  if ((options & PCRE_EXTENDED) != 0)
   {    {
   for (;;)    for (;;)
     {      {
    while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++;    while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_space) != 0) ptr++;
     if (*ptr == CHAR_NUMBER_SIGN)      if (*ptr == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
Line 2896  if ((options & PCRE_EXTENDED) != 0) Line 3014  if ((options & PCRE_EXTENDED) != 0)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }          if (IS_NEWLINE(ptr)) { 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
         }          }
       }        }
Line 2908  if ((options & PCRE_EXTENDED) != 0) Line 3026  if ((options & PCRE_EXTENDED) != 0)
 /* If the next thing is itself optional, we have to give up. */  /* If the next thing is itself optional, we have to give up. */
   
 if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK ||  if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK ||
  strncmp((char *)ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0)  STRNCMP_UC_C8(ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0)
     return FALSE;      return FALSE;
   
 /* Now compare the next item with the previous opcode. First, handle cases when  /* Now compare the next item with the previous opcode. First, handle cases when
Line 2917  the next item is a character. */ Line 3035  the next item is a character. */
 if (next >= 0) switch(op_code)  if (next >= 0) switch(op_code)
   {    {
   case OP_CHAR:    case OP_CHAR:
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
   GETCHARTEST(c, previous);    GETCHARTEST(c, previous);
 #else  #else
   c = *previous;    c = *previous;
Line 2929  if (next >= 0) switch(op_code) Line 3047  if (next >= 0) switch(op_code)
   high-valued characters. */    high-valued characters. */
   
   case OP_CHARI:    case OP_CHARI:
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
   GETCHARTEST(c, previous);    GETCHARTEST(c, previous);
 #else  #else
   c = *previous;    c = *previous;
 #endif  #endif
   if (c == next) return FALSE;    if (c == next) return FALSE;
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
  if (utf8)  if (utf)
     {      {
     unsigned int othercase;      unsigned int othercase;
     if (next < 128) othercase = cd->fcc[next]; else      if (next < 128) othercase = cd->fcc[next]; else
Line 2948  if (next >= 0) switch(op_code) Line 3066  if (next >= 0) switch(op_code)
     return (unsigned int)c != othercase;      return (unsigned int)c != othercase;
     }      }
   else    else
#endif  /* SUPPORT_UTF8 */#endif  /* SUPPORT_UTF */
  return (c != cd->fcc[next]);  /* Non-UTF-8 mode */  return (c != TABLE_GET((unsigned int)next, cd->fcc, next));  /* Non-UTF-8 mode */
   
   /* For OP_NOT and OP_NOTI, the data is always a single-byte character. These    /* For OP_NOT and OP_NOTI, the data is always a single-byte character. These
   opcodes are not used for multi-byte characters, because they are coded using    opcodes are not used for multi-byte characters, because they are coded using
Line 2960  if (next >= 0) switch(op_code) Line 3078  if (next >= 0) switch(op_code)
   
   case OP_NOTI:    case OP_NOTI:
   if ((c = *previous) == next) return TRUE;    if ((c = *previous) == next) return TRUE;
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
  if (utf8)  if (utf)
     {      {
     unsigned int othercase;      unsigned int othercase;
     if (next < 128) othercase = cd->fcc[next]; else      if (next < 128) othercase = cd->fcc[next]; else
Line 2973  if (next >= 0) switch(op_code) Line 3091  if (next >= 0) switch(op_code)
     return (unsigned int)c == othercase;      return (unsigned int)c == othercase;
     }      }
   else    else
#endif  /* SUPPORT_UTF8 */#endif  /* SUPPORT_UTF */
  return (c == cd->fcc[next]);  /* Non-UTF-8 mode */  return (c == (int)(TABLE_GET((unsigned int)next, cd->fcc, next)));  /* Non-UTF-8 mode */
   
   /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* set.    /* 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. */    When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
Line 3065  switch(op_code) Line 3183  switch(op_code)
   {    {
   case OP_CHAR:    case OP_CHAR:
   case OP_CHARI:    case OP_CHARI:
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
   GETCHARTEST(c, previous);    GETCHARTEST(c, previous);
 #else  #else
   c = *previous;    c = *previous;
Line 3170  switch(op_code) Line 3288  switch(op_code)
       to the original \d etc. At this point, ptr will point to a zero byte. */        to the original \d etc. At this point, ptr will point to a zero byte. */
   
       if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK ||        if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MARK ||
        strncmp((char *)ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0)        STRNCMP_UC_C8(ptr, STR_LEFT_CURLY_BRACKET STR_0 STR_COMMA, 3) == 0)
           return FALSE;            return FALSE;
   
       /* Do the property check. */        /* Do the property check. */
Line 3248  Arguments: Line 3366  Arguments:
   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   set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
  reqbyteptr     set to the last literal character required, else < 0  reqcharptr     set to the last literal character required, else < 0
   bcptr          points to current branch chain    bcptr          points to current branch chain
   cond_depth     conditional nesting depth    cond_depth     conditional nesting depth
   cd             contains pointers to tables etc.    cd             contains pointers to tables etc.
Line 3261  Returns:         TRUE on success Line 3379  Returns:         TRUE on success
 */  */
   
 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, pcre_int32 *firstcharptr,
  int cond_depth, compile_data *cd, int *lengthptr)  pcre_int32 *reqcharptr, 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_int32 firstchar, reqchar;
int zeroreqbyte, zerofirstbyte;pcre_int32 zeroreqchar, zerofirstchar;
int req_caseopt, reqvary, tempreqvary;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 int c;
register uschar *code = *codeptr;register pcre_uchar *code = *codeptr;
uschar *last_code = code;pcre_uchar *last_code = code;
uschar *orig_code = code;pcre_uchar *orig_code = code;
uschar *tempcode;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_UTF16 has the same value as PCRE_UTF8. */
BOOL utf8 = (options & PCRE_UTF8) != 0;BOOL utf = (options & PCRE_UTF8) != 0;
uschar *class_utf8data;pcre_uchar utf_chars[6];
uschar *class_utf8data_base; 
uschar utf8_char[6]; 
 #else  #else
BOOL utf8 = FALSE;BOOL utf = FALSE;
 #endif  #endif
   
   /* Helper variables for OP_XCLASS opcode (for characters > 255). */
   
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
   BOOL xclass;
   pcre_uchar *class_uchardata;
   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 3440  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 = 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 3468  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_single_char;
   int newoptions;    int newoptions;
   int recno;    int recno;
   int refsign;    int refsign;
   int skipbytes;    int skipbytes;
  int subreqbyte;  int subreqchar;
  int subfirstbyte;  int subfirstchar;
   int terminator;    int terminator;
   int mclength;    int mclength;
   int tempbracount;    int tempbracount;
  uschar mcbuffer[8];  pcre_uchar mcbuffer[8];
   
  /* Get next byte in the pattern */  /* Get next character in the pattern */
   
   c = *ptr;    c = *ptr;
   
Line 3401  for (;; ptr++) Line 3527  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 3538  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 3481  for (;; ptr++) Line 3607  for (;; ptr++)
   
   if ((options & PCRE_EXTENDED) != 0)    if ((options & PCRE_EXTENDED) != 0)
     {      {
    if ((cd->ctypes[c] & ctype_space) != 0) continue;    if (MAX_255(*ptr) && (cd->ctypes[c] & ctype_space) != 0) continue;
     if (c == CHAR_NUMBER_SIGN)      if (c == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
Line 3489  for (;; ptr++) Line 3615  for (;; ptr++)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }          if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; 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;        if (*ptr != 0) continue;
Line 3514  for (;; ptr++) Line 3640  for (;; ptr++)
     case 0:                        /* The branch terminates at string end */      case 0:                        /* 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;    *reqcharptr = reqchar;
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
     if (lengthptr != NULL)      if (lengthptr != NULL)
Line 3539  for (;; ptr++) Line 3665  for (;; ptr++)
     previous = NULL;      previous = NULL;
     if ((options & PCRE_MULTILINE) != 0)      if ((options & PCRE_MULTILINE) != 0)
       {        {
      if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;      if (firstchar == REQ_UNSET) firstchar = REQ_NONE;
       *code++ = OP_CIRCM;        *code++ = OP_CIRCM;
       }        }
     else *code++ = OP_CIRC;      else *code++ = OP_CIRC;
Line 3551  for (;; ptr++) Line 3677  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 (firstchar == REQ_UNSET) firstchar = REQ_NONE;
    zerofirstbyte = firstbyte;    zerofirstchar = firstchar;
    zeroreqbyte = reqbyte;    zeroreqchar = reqchar;
     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 3611  for (;; ptr++) Line 3737  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 3756  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 (firstchar == REQ_UNSET) firstchar = REQ_NONE;
      zerofirstbyte = firstbyte;      zerofirstchar = firstchar;
       break;        break;
       }        }
   
Line 3642  for (;; ptr++) Line 3767  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_single_char will be 1 if the class contains only
     a single character. */
   
    class_charcount = 0;    class_has_8bitchar = 0;
    class_lastchar = -1;    class_single_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 only 1 character (less
     than 256), because in that case the compiled code doesn't use the bit map.      than 256), 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;                           /* No chars >= 256 */
    class_utf8data = code + LINK_SIZE + 2;    /* For UTF-8 items */    class_uchardata = code + LINK_SIZE + 2;   /* For UTF-8 items */
    class_utf8data_base = class_utf8data;     /* For resetting in pass 1 */    class_uchardata_base = class_uchardata;   /* For resetting in pass 1 */
 #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
Line 3668  for (;; ptr++) Line 3794  for (;; ptr++)
   
     if (c != 0) do      if (c != 0) 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). */
   
       if (lengthptr != NULL)        if (lengthptr != NULL)
         {          {
        *lengthptr += (int)(class_utf8data - class_utf8data_base);        *lengthptr += class_uchardata - class_uchardata_base;
        class_utf8data = class_utf8data_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 3841  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 3770  for (;; ptr++) Line 3897  for (;; ptr++)
         /* 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 3801  for (;; ptr++) Line 3928  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 characters. */
         class_has_8bitchar = 1;
         /* Every class contains at least two characters. */
         class_single_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_single_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)
Line 3837  for (;; ptr++) Line 3968  for (;; ptr++)
   
         if (c < 0)          if (c < 0)
           {            {
          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_single_char += 2;
   
           switch (-c)            switch (-c)
             {              {
Line 3851  for (;; ptr++) Line 3985  for (;; ptr++)
             case ESC_SU:              case ESC_SU:
             nestptr = ptr;              nestptr = ptr;
             ptr = substitutes[-c - ESC_DU] - 1;  /* Just before substitute */              ptr = substitutes[-c - 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 3892  for (;; ptr++) Line 4026  for (;; ptr++)
             SETBIT(classbits, 0x09); /* VT */              SETBIT(classbits, 0x09); /* VT */
             SETBIT(classbits, 0x20); /* SPACE */              SETBIT(classbits, 0x20); /* SPACE */
             SETBIT(classbits, 0xa0); /* NSBP */              SETBIT(classbits, 0xa0); /* NSBP */
#ifdef SUPPORT_UTF8#ifndef COMPILE_PCRE8
            if (utf8)            xclass = TRUE;
             *class_uchardata++ = XCL_SINGLE;
             *class_uchardata++ = 0x1680;
             *class_uchardata++ = XCL_SINGLE;
             *class_uchardata++ = 0x180e;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x2000;
             *class_uchardata++ = 0x200a;
             *class_uchardata++ = XCL_SINGLE;
             *class_uchardata++ = 0x202f;
             *class_uchardata++ = XCL_SINGLE;
             *class_uchardata++ = 0x205f;
             *class_uchardata++ = XCL_SINGLE;
             *class_uchardata++ = 0x3000;
 #elif defined SUPPORT_UTF
             if (utf)
               {                {
              class_utf8 = TRUE;              xclass = TRUE;
              *class_utf8data++ = XCL_SINGLE;              *class_uchardata++ = XCL_SINGLE;
              class_utf8data += _pcre_ord2utf8(0x1680, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x1680, class_uchardata);
              *class_utf8data++ = XCL_SINGLE;              *class_uchardata++ = XCL_SINGLE;
              class_utf8data += _pcre_ord2utf8(0x180e, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x180e, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x2000, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2000, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x200A, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x200a, class_uchardata);
              *class_utf8data++ = XCL_SINGLE;              *class_uchardata++ = XCL_SINGLE;
              class_utf8data += _pcre_ord2utf8(0x202f, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x202f, class_uchardata);
              *class_utf8data++ = XCL_SINGLE;              *class_uchardata++ = XCL_SINGLE;
              class_utf8data += _pcre_ord2utf8(0x205f, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x205f, class_uchardata);
              *class_utf8data++ = XCL_SINGLE;              *class_uchardata++ = XCL_SINGLE;
              class_utf8data += _pcre_ord2utf8(0x3000, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x3000, class_uchardata);
               }                }
 #endif  #endif
             continue;              continue;
Line 3926  for (;; ptr++) Line 4075  for (;; ptr++)
                 }                  }
               classbits[c] |= x;                classbits[c] |= x;
               }                }
#ifndef COMPILE_PCRE8
#ifdef SUPPORT_UTF8            xclass = TRUE;
            if (utf8)            *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x0100;
             *class_uchardata++ = 0x167f;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x1681;
             *class_uchardata++ = 0x180d;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x180f;
             *class_uchardata++ = 0x1fff;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x200b;
             *class_uchardata++ = 0x202e;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x2030;
             *class_uchardata++ = 0x205e;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x2060;
             *class_uchardata++ = 0x2fff;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x3001;
 #ifdef SUPPORT_UTF
             if (utf)
               class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
             else
 #endif
               *class_uchardata++ = 0xffff;
 #elif defined SUPPORT_UTF
             if (utf)
               {                {
              class_utf8 = TRUE;              xclass = TRUE;
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x167f, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x167f, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x1681, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x1681, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x180d, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x180d, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x180f, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x180f, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x1fff, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x1fff, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x200B, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x200b, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x202e, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x202e, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x2030, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2030, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x205e, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x205e, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x2060, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2060, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x2fff, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2fff, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x3001, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x3001, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
               }                }
 #endif  #endif
             continue;              continue;
Line 3962  for (;; ptr++) Line 4138  for (;; ptr++)
             SETBIT(classbits, 0x0c); /* FF */              SETBIT(classbits, 0x0c); /* FF */
             SETBIT(classbits, 0x0d); /* CR */              SETBIT(classbits, 0x0d); /* CR */
             SETBIT(classbits, 0x85); /* NEL */              SETBIT(classbits, 0x85); /* NEL */
#ifdef SUPPORT_UTF8#ifndef COMPILE_PCRE8
            if (utf8)            xclass = TRUE;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x2028;
             *class_uchardata++ = 0x2029;
 #elif defined SUPPORT_UTF
             if (utf)
               {                {
              class_utf8 = TRUE;              xclass = TRUE;
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x2028, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2028, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2029, class_uchardata);
               }                }
 #endif  #endif
             continue;              continue;
Line 3990  for (;; ptr++) Line 4171  for (;; ptr++)
               classbits[c] |= x;                classbits[c] |= x;
               }                }
   
#ifdef SUPPORT_UTF8#ifndef COMPILE_PCRE8
            if (utf8)            xclass = TRUE;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x0100;
             *class_uchardata++ = 0x2027;
             *class_uchardata++ = XCL_RANGE;
             *class_uchardata++ = 0x202a;
 #ifdef SUPPORT_UTF
             if (utf)
               class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
             else
 #endif
               *class_uchardata++ = 0xffff;
 #elif defined SUPPORT_UTF
             if (utf)
               {                {
              class_utf8 = TRUE;              xclass = TRUE;
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x0100, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x2027, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x2027, class_uchardata);
              *class_utf8data++ = XCL_RANGE;              *class_uchardata++ = XCL_RANGE;
              class_utf8data += _pcre_ord2utf8(0x2029, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x202a, class_uchardata);
              class_utf8data += _pcre_ord2utf8(0x7fffffff, class_utf8data);              class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
               }                }
 #endif  #endif
             continue;              continue;
Line 4012  for (;; ptr++) Line 4206  for (;; ptr++)
               int pdata;                int pdata;
               int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);                int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);
               if (ptype < 0) goto FAILED;                if (ptype < 0) goto FAILED;
              class_utf8 = TRUE;              xclass = TRUE;
              *class_utf8data++ = ((-c == ESC_p) != negated)?              *class_uchardata++ = ((-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 4225  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_single_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 we have a single character (c >= 0). This may be
        greater than 256 in UTF-8 mode. */        greater than 256. */
   
         }   /* End of backslash handling */          }   /* End of backslash handling */
   
Line 4086  for (;; ptr++) Line 4281  for (;; ptr++)
           goto LONE_SINGLE_CHARACTER;            goto LONE_SINGLE_CHARACTER;
           }            }
   
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
        if (utf8)        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 4131  for (;; ptr++) Line 4326  for (;; ptr++)
   
         if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;          if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
   
           /* Since we found a character range, single character optimizations
           cannot be done anymore. */
           class_single_char = 2;
   
         /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless          /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless
         matching, we have to use an XCLASS with extra data items. Caseless          matching, we have to use an XCLASS with extra data items. Caseless
         matching for characters > 127 is available only if UCP support is          matching for characters > 127 is available only if UCP support is
         available. */          available. */
   
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF && !(defined COMPILE_PCRE8)
        if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))        if ((d > 255) || (utf && ((options & PCRE_CASELESS) != 0 && d > 127)))
 #elif defined  SUPPORT_UTF
         if (utf && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))
 #elif !(defined COMPILE_PCRE8)
         if (d > 255)
 #endif
 #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
           {            {
          class_utf8 = TRUE;          xclass = TRUE;
   
           /* With UCP support, we can find the other case equivalents of            /* With UCP support, we can find the other case equivalents of
           the relevant characters. There may be several ranges. Optimize how            the relevant characters. There may be several ranges. Optimize how
           they fit with the basic range. */            they fit with the basic range. */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
   #ifndef COMPILE_PCRE8
             if (utf && (options & PCRE_CASELESS) != 0)
   #else
           if ((options & PCRE_CASELESS) != 0)            if ((options & PCRE_CASELESS) != 0)
   #endif
             {              {
             unsigned int occ, ocd;              unsigned int occ, ocd;
             unsigned int cc = c;              unsigned int cc = c;
Line 4172  for (;; ptr++) Line 4381  for (;; ptr++)
   
               if (occ == ocd)                if (occ == ocd)
                 {                  {
                *class_utf8data++ = XCL_SINGLE;                *class_uchardata++ = XCL_SINGLE;
                 }                  }
               else                else
                 {                  {
                *class_utf8data++ = XCL_RANGE;                *class_uchardata++ = XCL_RANGE;
                class_utf8data += _pcre_ord2utf8(occ, class_utf8data);                class_uchardata += PRIV(ord2utf)(occ, class_uchardata);
                 }                  }
              class_utf8data += _pcre_ord2utf8(ocd, class_utf8data);              class_uchardata += PRIV(ord2utf)(ocd, class_uchardata);
               }                }
             }              }
 #endif  /* SUPPORT_UCP */  #endif  /* SUPPORT_UCP */
Line 4187  for (;; ptr++) Line 4396  for (;; ptr++)
           /* Now record the original range, possibly modified for UCP caseless            /* Now record the original range, possibly modified for UCP caseless
           overlapping ranges. */            overlapping ranges. */
   
          *class_utf8data++ = XCL_RANGE;          *class_uchardata++ = XCL_RANGE;
          class_utf8data += _pcre_ord2utf8(c, class_utf8data);#ifdef SUPPORT_UTF
          class_utf8data += _pcre_ord2utf8(d, class_utf8data);#ifndef COMPILE_PCRE8
           if (utf)
             {
             class_uchardata += PRIV(ord2utf)(c, class_uchardata);
             class_uchardata += PRIV(ord2utf)(d, class_uchardata);
             }
           else
             {
             *class_uchardata++ = c;
             *class_uchardata++ = d;
             }
 #else
           class_uchardata += PRIV(ord2utf)(c, class_uchardata);
           class_uchardata += PRIV(ord2utf)(d, class_uchardata);
 #endif
 #else /* SUPPORT_UTF */
           *class_uchardata++ = c;
           *class_uchardata++ = d;
 #endif /* SUPPORT_UTF */
   
           /* With UCP support, we are done. Without UCP support, there is no            /* 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          caseless matching for UTF characters > 127; we can use the bit map
          for the smaller ones. */          for the smaller ones. As for 16 bit characters without UTF, we
           can still use  */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
          continue;    /* With next character in the class */#ifndef COMPILE_PCRE8
#else          if (utf)
          if ((options & PCRE_CASELESS) == 0 || c > 127) continue;#endif
             continue;    /* With next character in the class */
 #endif  /* SUPPORT_UCP */
   
   #if defined SUPPORT_UTF && !defined(SUPPORT_UCP) && !(defined COMPILE_PCRE8)
             if (utf)
               {
               if ((options & PCRE_CASELESS) == 0 || c > 127) continue;
               /* Adjust upper limit and fall through to set up the map */
               d = 127;
               }
             else
               {
               if (c > 255) continue;
               /* Adjust upper limit and fall through to set up the map */
               d = 255;
               }
   #elif defined SUPPORT_UTF && !defined(SUPPORT_UCP)
             if ((options & PCRE_CASELESS) == 0 || c > 127) continue;
           /* Adjust upper limit and fall through to set up the map */            /* Adjust upper limit and fall through to set up the map */
   
           d = 127;            d = 127;
#else
#endif  /* SUPPORT_UCP */          if (c > 255) continue;
           /* Adjust upper limit and fall through to set up the map */
           d = 255;
 #endif  /* SUPPORT_UTF && !SUPPORT_UCP && !COMPILE_PCRE8 */
           }            }
#endif  /* SUPPORT_UTF8 */#endif  /* SUPPORT_UTF || !COMPILE_PCRE8 */
   
        /* We use the bit map for all cases when not in UTF-8 mode; else        /* We use the bit map for 8 bit mode, or when the characters fall
        ranges that lie entirely within 0-127 when there is UCP support; else        partially or entirely to [0-255] ([0-127] for UCP) ranges. */
        for partial ranges without UCP support. */ 
   
        class_charcount += d - c + 1;        class_has_8bitchar = 1;
        class_lastchar = d; 
   
         /* We can save a bit of time by skipping this in the pre-compile. */          /* We can save a bit of time by skipping this in the pre-compile. */
   
Line 4222  for (;; ptr++) Line 4467  for (;; ptr++)
           classbits[c/8] |= (1 << (c&7));            classbits[c/8] |= (1 << (c&7));
           if ((options & PCRE_CASELESS) != 0)            if ((options & PCRE_CASELESS) != 0)
             {              {
            int uc = cd->fcc[c];           /* flip case */            int uc = cd->fcc[c]; /* flip case */
             classbits[uc/8] |= (1 << (uc&7));              classbits[uc/8] |= (1 << (uc&7));
             }              }
           }            }
Line 4236  for (;; ptr++) Line 4481  for (;; ptr++)
   
       LONE_SINGLE_CHARACTER:        LONE_SINGLE_CHARACTER:
   
      /* Handle a character that cannot go in the bit map */      /* Only the value of 1 matters for class_single_char. */
       if (class_single_char < 2) class_single_char++;
   
#ifdef SUPPORT_UTF8      /* If class_charcount is 1, we saw precisely one character. As long as
      if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127)))      there were no negated characters >= 128 and there was no use of \p or \P,
       in other words, no use of any XCLASS features, we can optimize.
 
       In UTF-8 mode, we can optimize the negative case only if there were no
       characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR
       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 firstchar to be set. Otherwise, there can be no first
       char if this item is first, whatever repeat count may follow. In the case
       of reqchar, save the previous value for reinstating. */
 
 #ifdef SUPPORT_UTF
       if (class_single_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET
         && (!utf || !negate_class || c < (MAX_VALUE_FOR_SINGLE_CHAR + 1)))
 #else
       if (class_single_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
 #endif
         {          {
        class_utf8 = TRUE;        ptr++;
        *class_utf8data++ = XCL_SINGLE;        zeroreqchar = reqchar;
        class_utf8data += _pcre_ord2utf8(c, class_utf8data); 
   
           /* The OP_NOT[I] opcodes work on single characters only. */
   
           if (negate_class)
             {
             if (firstchar == REQ_UNSET) firstchar = REQ_NONE;
             zerofirstchar = firstchar;
             *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;
             *code++ = c;
             goto NOT_CHAR;
             }
   
           /* For a single, positive character, get the value into mcbuffer, and
           then we can handle this with the normal one-character code. */
   
   #ifdef SUPPORT_UTF
           if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
             mclength = PRIV(ord2utf)(c, mcbuffer);
           else
   #endif
             {
             mcbuffer[0] = c;
             mclength = 1;
             }
           goto ONE_CHAR;
           }       /* End of 1-char optimization */
   
         /* Handle a character that cannot go in the bit map. */
   
   #if defined SUPPORT_UTF && !(defined COMPILE_PCRE8)
         if ((c > 255) || (utf && ((options & PCRE_CASELESS) != 0 && c > 127)))
   #elif defined SUPPORT_UTF
         if (utf && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127)))
   #elif !(defined COMPILE_PCRE8)
         if (c > 255)
   #endif
   
   #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
           {
           xclass = TRUE;
           *class_uchardata++ = XCL_SINGLE;
   #ifdef SUPPORT_UTF
   #ifndef COMPILE_PCRE8
           /* In non 8 bit mode, we can get here even if we are not in UTF mode. */
           if (!utf)
             *class_uchardata++ = c;
           else
   #endif
             class_uchardata += PRIV(ord2utf)(c, class_uchardata);
   #else /* SUPPORT_UTF */
           *class_uchardata++ = c;
   #endif /* SUPPORT_UTF */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
   #ifdef COMPILE_PCRE8
         if ((options & PCRE_CASELESS) != 0)          if ((options & PCRE_CASELESS) != 0)
   #else
           /* In non 8 bit mode, we can get here even if we are not in UTF mode. */
           if (utf && (options & PCRE_CASELESS) != 0)
   #endif
           {            {
           unsigned int othercase;            unsigned int othercase;
          if ((othercase = UCD_OTHERCASE(c)) != c)          if ((int)(othercase = UCD_OTHERCASE(c)) != c)
             {              {
            *class_utf8data++ = XCL_SINGLE;            *class_uchardata++ = XCL_SINGLE;
            class_utf8data += _pcre_ord2utf8(othercase, class_utf8data);            class_uchardata += PRIV(ord2utf)(othercase, class_uchardata);
             }              }
           }            }
 #endif  /* SUPPORT_UCP */  #endif  /* SUPPORT_UCP */
   
         }          }
       else        else
#endif  /* SUPPORT_UTF8 */#endif  /* SUPPORT_UTF || COMPILE_PCRE16 */
   
       /* Handle a single-byte character */        /* Handle a single-byte character */
         {          {
           class_has_8bitchar = 1;
         classbits[c/8] |= (1 << (c&7));          classbits[c/8] |= (1 << (c&7));
         if ((options & PCRE_CASELESS) != 0)          if ((options & PCRE_CASELESS) != 0)
           {            {
          c = cd->fcc[c];   /* flip case */          c = cd->fcc[c]; /* flip case */
           classbits[c/8] |= (1 << (c&7));            classbits[c/8] |= (1 << (c&7));
           }            }
         class_charcount++;  
         class_lastchar = c;  
         }          }
       }        }
   
Line 4291  for (;; ptr++) Line 4612  for (;; ptr++)
       goto FAILED;        goto FAILED;
       }        }
   
    /* If class_charcount is 1, we saw precisely one character whose value is    /* If this is the first thing in the branch, there can be no first char
    less than 256. As long as there were no characters >= 128 and there was no    setting, whatever the repeat count. Any reqchar setting must remain
    use of \p or \P, in other words, no use of any XCLASS features, we can    unchanged after any kind of repeat. */
    optimize. 
   
    In UTF-8 mode, we can optimize the negative case only if there were no    if (firstchar == REQ_UNSET) firstchar = REQ_NONE;
    characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR    zerofirstchar = firstchar;
    operate on single-bytes characters only. This is an historical hangover.    zeroreqchar = reqchar;
    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  
       {  
       zeroreqbyte = reqbyte;  
   
       /* The OP_NOT[I] opcodes work on one-byte characters only. */  
   
       if (negate_class)  
         {  
         if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;  
         zerofirstbyte = firstbyte;  
         *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;  
         *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 4628  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 4667  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);
     NOT_CHAR:
     break;      break;
   
   
Line 4440  for (;; ptr++) Line 4711  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 */      reqchar = zeroreqchar;        /* Ditto */
       }        }
   
     /* Remember whether this is a variable length repeat */      /* Remember whether this is a variable length repeat */
Line 4483  for (;; ptr++) Line 4754  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 4506  for (;; ptr++) Line 4777  for (;; ptr++)
   
     /* If previous was a character match, abolish the item and generate a      /* If previous was a character match, abolish the item and generate a
     repeat item instead. If a char item has a minumum of more than one, ensure      repeat item instead. If a char item has a minumum of more than one, ensure
    that it is set in reqbyte - it might not be if a sequence such as x{3} is    that it is set in reqchar - it might not be if a sequence such as x{3} is
    the first thing in a branch because the x will have gone into firstbyte    the first thing in a branch because the x will have gone into firstchar
     instead.  */      instead.  */
   
     if (*previous == OP_CHAR || *previous == OP_CHARI)      if (*previous == OP_CHAR || *previous == OP_CHARI)
       {        {
       op_type = (*previous == OP_CHAR)? 0 : OP_STARI - OP_STAR;        op_type = (*previous == OP_CHAR)? 0 : OP_STARI - OP_STAR;
   
      /* 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#ifdef SUPPORT_UTF
      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 (repeat_min > 1) reqchar = c | req_caseopt | cd->req_varyopt;
         }          }
   
       /* If the repetition is unlimited, it pays to see if the next thing on        /* If the repetition is unlimited, it pays to see if the next thing on
Line 4546  for (;; ptr++) Line 4816  for (;; ptr++)
   
       if (!possessive_quantifier &&        if (!possessive_quantifier &&
           repeat_max < 0 &&            repeat_max < 0 &&
          check_auto_possessive(previous, utf8, ptr + 1, options, cd))          check_auto_possessive(previous, utf, ptr + 1, options, cd))
         {          {
         repeat_type = 0;    /* Force greedy */          repeat_type = 0;    /* Force greedy */
         possessive_quantifier = TRUE;          possessive_quantifier = TRUE;
Line 4567  for (;; ptr++) Line 4837  for (;; ptr++)
       c = previous[1];        c = previous[1];
       if (!possessive_quantifier &&        if (!possessive_quantifier &&
           repeat_max < 0 &&            repeat_max < 0 &&
          check_auto_possessive(previous, utf8, ptr + 1, options, cd))          check_auto_possessive(previous, utf, ptr + 1, options, cd))
         {          {
         repeat_type = 0;    /* Force greedy */          repeat_type = 0;    /* Force greedy */
         possessive_quantifier = TRUE;          possessive_quantifier = TRUE;
Line 4584  for (;; ptr++) Line 4854  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 &&        if (!possessive_quantifier &&
           repeat_max < 0 &&            repeat_max < 0 &&
          check_auto_possessive(previous, utf8, ptr + 1, options, cd))          check_auto_possessive(previous, utf, ptr + 1, options, cd))
         {          {
         repeat_type = 0;    /* Force greedy */          repeat_type = 0;    /* Force greedy */
         possessive_quantifier = TRUE;          possessive_quantifier = TRUE;
Line 4671  for (;; ptr++) Line 4941  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#ifdef SUPPORT_UTF
          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 4970  for (;; ptr++)
   
         else if (repeat_max != repeat_min)          else if (repeat_max != repeat_min)
           {            {
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
          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 5000  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#ifdef SUPPORT_UTF
      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 4757  for (;; ptr++) Line 5027  for (;; ptr++)
   
     else if (*previous == OP_CLASS ||      else if (*previous == OP_CLASS ||
              *previous == OP_NCLASS ||               *previous == OP_NCLASS ||
#ifdef SUPPORT_UTF8#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
              *previous == OP_XCLASS ||               *previous == OP_XCLASS ||
 #endif  #endif
              *previous == OP_REF ||               *previous == OP_REF ||
Line 4806  for (;; ptr++) Line 5076  for (;; ptr++)
       {        {
       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 4860  for (;; ptr++) Line 5130  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 5154  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 5208  for (;; ptr++)
   
           else            else
             {              {
            if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte;            if (groupsetfirstchar && reqchar < 0) reqchar = firstchar;
   
             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 5223  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 5276  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 5293  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 5305  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 5325  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 5361  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 5384  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))
                 {                  {
                 *bracode += OP_SBRA - OP_BRA;                  *bracode += OP_SBRA - OP_BRA;
                 break;                  break;
Line 5140  for (;; ptr++) Line 5410  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 5210  for (;; ptr++) Line 5480  for (;; ptr++)
       int len;        int len;
   
       if (*tempcode == OP_TYPEEXACT)        if (*tempcode == OP_TYPEEXACT)
        tempcode += _pcre_OP_lengths[*tempcode] +        tempcode += PRIV(OP_lengths)[*tempcode] +
          ((tempcode[3] == OP_PROP || tempcode[3] == OP_NOTPROP)? 2 : 0);          ((tempcode[1 + IMM2_SIZE] == OP_PROP
           || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
   
       else if (*tempcode == OP_EXACT || *tempcode == OP_NOTEXACT)        else if (*tempcode == OP_EXACT || *tempcode == OP_NOTEXACT)
         {          {
        tempcode += _pcre_OP_lengths[*tempcode];        tempcode += PRIV(OP_lengths)[*tempcode];
#ifdef SUPPORT_UTF8#ifdef SUPPORT_UTF
        if (utf8 && tempcode[-1] >= 0xc0)        if (utf && HAS_EXTRALEN(tempcode[-1]))
          tempcode += _pcre_utf8_table4[tempcode[-1] & 0x3f];          tempcode += GET_EXTRALEN(tempcode[-1]);
 #endif  #endif
         }          }
   
Line 5255  for (;; ptr++) Line 5526  for (;; ptr++)
   
         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 5268  for (;; ptr++) Line 5539  for (;; ptr++)
       }        }
   
     /* 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 5562  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 5325  for (;; ptr++) Line 5598  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)
           {            {
           /* 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 5346  for (;; ptr++) Line 5619  for (;; ptr++)
               }                }
             *code++ = (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;              *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 (firstchar == REQ_UNSET) firstchar = REQ_NONE;
             }              }
   
           /* Handle other cases with/without an argument */            /* Handle other cases with/without an argument */
Line 5373  for (;; ptr++) Line 5646  for (;; ptr++)
             *code = verbs[i].op_arg;              *code = verbs[i].op_arg;
             if (*code++ == OP_THEN_ARG) cd->external_flags |= PCRE_HASTHEN;              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;
             }              }
Line 5396  for (;; ptr++) Line 5669  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))
         {          {
Line 5450  for (;; ptr++) Line 5723  for (;; ptr++)
           break;            break;
   
         /* Most other conditions use OP_CREF (a couple change to OP_RREF          /* Most other conditions use OP_CREF (a couple change to OP_RREF
        below), and all need to skip 3 bytes at the start of the group. */        below), and all need to skip 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. */
Line 5486  for (;; ptr++) Line 5759  for (;; ptr++)
   
         /* We now expect to read a name; any thing else is an error */          /* We now expect to read a name; any thing else is an error */
   
        if ((cd->ctypes[ptr[1]] & ctype_word) == 0)        if (!MAX_255(ptr[1]) || (cd->ctypes[ptr[1]] & ctype_word) == 0)
           {            {
           ptr += 1;  /* To get the right offset */            ptr += 1;  /* To get the right offset */
           *errorcodeptr = ERR28;            *errorcodeptr = ERR28;
Line 5497  for (;; ptr++) Line 5770  for (;; ptr++)
   
         recno = 0;          recno = 0;
         name = ++ptr;          name = ++ptr;
        while ((cd->ctypes[*ptr] & ctype_word) != 0)        while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0)
           {            {
           if (recno >= 0)            if (recno >= 0)
            recno = ((digitab[*ptr] & ctype_digit) != 0)?            recno = (IS_DIGIT(*ptr))? recno * 10 + *ptr - CHAR_0 : -1;
              recno * 10 + *ptr - CHAR_0 : -1; 
           ptr++;            ptr++;
           }            }
         namelen = (int)(ptr - name);          namelen = (int)(ptr - name);
Line 5549  for (;; ptr++) Line 5821  for (;; ptr++)
         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;
           }            }
   
Line 5565  for (;; ptr++) Line 5837  for (;; ptr++)
         /* Search the pattern for a forward reference */          /* Search the pattern for a forward reference */
   
         else if ((i = find_parens(cd, name, namelen,          else if ((i = find_parens(cd, name, namelen,
                        (options & PCRE_EXTENDED) != 0, utf8)) > 0)                        (options & PCRE_EXTENDED) != 0, utf)) > 0)
           {            {
           PUT2(code, 2+LINK_SIZE, i);            PUT2(code, 2+LINK_SIZE, i);
           code[1+LINK_SIZE]++;            code[1+LINK_SIZE]++;
Line 5591  for (;; ptr++) Line 5863  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 5878  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;
Line 5669  for (;; ptr++) Line 5941  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 5964  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 5737  for (;; ptr++) Line 6011  for (;; ptr++)
             CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;              CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
           name = ++ptr;            name = ++ptr;
   
          while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;          while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
           namelen = (int)(ptr - name);            namelen = (int)(ptr - name);
   
           /* In the pre-compile phase, just do a syntax check. */            /* In the pre-compile phase, just do a syntax check. */
Line 5754  for (;; ptr++) Line 6028  for (;; ptr++)
               *errorcodeptr = ERR49;                *errorcodeptr = ERR49;
               goto FAILED;                goto FAILED;
               }                }
            if (namelen + 3 > cd->name_entry_size)            if (namelen + IMM2_SIZE + 1 > cd->name_entry_size)
               {                {
              cd->name_entry_size = namelen + 3;              cd->name_entry_size = namelen + IMM2_SIZE + 1;
               if (namelen > MAX_NAME_SIZE)                if (namelen > MAX_NAME_SIZE)
                 {                  {
                 *errorcodeptr = ERR48;                  *errorcodeptr = ERR48;
Line 5785  for (;; ptr++) Line 6059  for (;; ptr++)
   
             for (i = 0; i < cd->names_found; i++)              for (i = 0; i < cd->names_found; i++)
               {                {
              int crc = memcmp(name, slot+2, namelen);              int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(namelen));
               if (crc == 0)                if (crc == 0)
                 {                  {
                if (slot[2+namelen] == 0)                if (slot[IMM2_SIZE+namelen] == 0)
                   {                    {
                   if (GET2(slot, 0) != cd->bracount + 1 &&                    if (GET2(slot, 0) != cd->bracount + 1 &&
                       (options & PCRE_DUPNAMES) == 0)                        (options & PCRE_DUPNAMES) == 0)
Line 5809  for (;; ptr++) Line 6083  for (;; ptr++)
               if (crc < 0)                if (crc < 0)
                 {                  {
                 memmove(slot + cd->name_entry_size, slot,                  memmove(slot + cd->name_entry_size, slot,
                  (cd->names_found - i) * cd->name_entry_size);                  IN_UCHARS((cd->names_found - i) * cd->name_entry_size));
                 break;                  break;
                 }                  }
   
Line 5823  for (;; ptr++) Line 6097  for (;; ptr++)
   
             if (!dupname)              if (!dupname)
               {                {
              uschar *cslot = cd->name_table;              pcre_uchar *cslot = cd->name_table;
               for (i = 0; i < cd->names_found; i++)                for (i = 0; i < cd->names_found; i++)
                 {                  {
                 if (cslot != slot)                  if (cslot != slot)
Line 5840  for (;; ptr++) Line 6114  for (;; ptr++)
               }                }
   
             PUT2(slot, 0, cd->bracount + 1);              PUT2(slot, 0, cd->bracount + 1);
            memcpy(slot + 2, name, namelen);            memcpy(slot + IMM2_SIZE, name, IN_UCHARS(namelen));
            slot[2+namelen] = 0;            slot[IMM2_SIZE + namelen] = 0;
             }              }
           }            }
   
Line 5867  for (;; ptr++) Line 6141  for (;; ptr++)
   
         NAMED_REF_OR_RECURSE:          NAMED_REF_OR_RECURSE:
         name = ++ptr;          name = ++ptr;
        while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;        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 6153  for (;; ptr++)
   
         if (lengthptr != NULL)          if (lengthptr != NULL)
           {            {
          const uschar *temp;          const pcre_uchar *temp;
   
           if (namelen == 0)            if (namelen == 0)
             {              {
Line 5909  for (;; ptr++) Line 6183  for (;; ptr++)
           temp = cd->end_pattern;            temp = cd->end_pattern;
           cd->end_pattern = ptr;            cd->end_pattern = ptr;
           recno = find_parens(cd, name, namelen,            recno = find_parens(cd, name, namelen,
            (options & PCRE_EXTENDED) != 0, utf8);            (options & PCRE_EXTENDED) != 0, utf);
           cd->end_pattern = temp;            cd->end_pattern = temp;
           if (recno < 0) recno = 0;    /* Forward ref; set dummy number */            if (recno < 0) recno = 0;    /* Forward ref; set dummy number */
           }            }
Line 5924  for (;; ptr++) Line 6198  for (;; ptr++)
           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;
             }              }
Line 5936  for (;; ptr++) Line 6210  for (;; ptr++)
             }              }
           else if ((recno =                /* Forward back reference */            else if ((recno =                /* Forward back reference */
                     find_parens(cd, name, namelen,                      find_parens(cd, name, namelen,
                      (options & PCRE_EXTENDED) != 0, utf8)) <= 0)                      (options & PCRE_EXTENDED) != 0, utf)) <= 0)
             {              {
             *errorcodeptr = ERR15;              *errorcodeptr = ERR15;
             goto FAILED;              goto FAILED;
Line 5961  for (;; ptr++) Line 6235  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 6249  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 6257  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 != terminator)
Line 6040  for (;; ptr++) Line 6314  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 (find_parens(cd, NULL, recno,
                    (options & PCRE_EXTENDED) != 0, utf8) < 0)                    (options & PCRE_EXTENDED) != 0, utf) < 0)
                 {                  {
                 *errorcodeptr = ERR15;                  *errorcodeptr = ERR15;
                 goto FAILED;                  goto FAILED;
Line 6077  for (;; ptr++) Line 6351  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 6359  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 (firstchar == REQ_UNSET) firstchar = REQ_NONE;
         continue;          continue;
   
   
Line 6153  for (;; ptr++) Line 6427  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 6440  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 6477  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. Assertions used not to be repeatable,
Line 6229  for (;; ptr++) Line 6503  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 */         &subreqchar,                     /* For possible last char */
          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 6258  for (;; ptr++) Line 6532  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 6555  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 6565  for (;; ptr++)
           *errorcodeptr = ERR27;            *errorcodeptr = ERR27;
           goto FAILED;            goto FAILED;
           }            }
        if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE;        if (condcount == 1) subfirstchar = subreqchar = REQ_NONE;
         }          }
       }        }
   
Line 6335  for (;; ptr++) Line 6609  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;    zerofirstchar = firstchar;
    groupsetfirstbyte = FALSE;    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 (firstchar == REQ_UNSET)
         {          {
        if (subfirstbyte >= 0)        if (subfirstchar >= 0)
           {            {
          firstbyte = subfirstbyte;          firstchar = subfirstchar;
          groupsetfirstbyte = TRUE;          groupsetfirstchar = TRUE;
           }            }
        else firstbyte = REQ_NONE;        else firstchar = REQ_NONE;
        zerofirstbyte = REQ_NONE;        zerofirstchar = 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 (subfirstchar >= 0 && subreqchar < 0)
        subreqbyte = subfirstbyte | tempreqvary;        subreqchar = subfirstchar | 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 (subreqchar >= 0) reqchar = subreqchar;
       }        }
   
    /* 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 && subreqchar >= 0) reqchar = subreqchar;
     break;     /* End of processing '(' */      break;     /* End of processing '(' */
   
   
Line 6416  for (;; ptr++) Line 6690  for (;; ptr++)
       /* 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 (firstchar == REQ_UNSET && -c > ESC_b && -c < ESC_Z)
        firstbyte = REQ_NONE;        firstchar = 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;      zeroreqchar = reqchar;
   
       /* \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
Line 6433  for (;; ptr++) Line 6707  for (;; ptr++)
   
       if (-c == ESC_g)        if (-c == ESC_g)
         {          {
        const uschar *p;        const pcre_uchar *p;
         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;
Line 6450  for (;; ptr++) Line 6724  for (;; ptr++)
   
         if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS)          if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS)
           {            {
          BOOL isnumber = TRUE;          BOOL is_a_number = TRUE;
           for (p = ptr + 1; *p != 0 && *p != terminator; p++)            for (p = ptr + 1; *p != 0 && *p != terminator; p++)
             {              {
            if ((cd->ctypes[*p] & ctype_digit) == 0) isnumber = FALSE;            if (!MAX_255(*p)) { is_a_number = FALSE; break; }
             if ((cd->ctypes[*p] & ctype_digit) == 0) is_a_number = FALSE;
             if ((cd->ctypes[*p] & ctype_word) == 0) break;              if ((cd->ctypes[*p] & ctype_word) == 0) break;
             }              }
           if (*p != terminator)            if (*p != terminator)
Line 6461  for (;; ptr++) Line 6736  for (;; ptr++)
             *errorcodeptr = ERR57;              *errorcodeptr = ERR57;
             break;              break;
             }              }
          if (isnumber)          if (is_a_number)
             {              {
             ptr++;              ptr++;
             goto HANDLE_NUMERICAL_RECURSION;              goto HANDLE_NUMERICAL_RECURSION;
Line 6473  for (;; ptr++) Line 6748  for (;; ptr++)
         /* Test a signed number in angle brackets or quotes. */          /* Test a signed number in angle brackets or quotes. */
   
         p = ptr + 2;          p = ptr + 2;
        while ((digitab[*p] & ctype_digit) != 0) p++;        while (IS_DIGIT(*p)) p++;
         if (*p != terminator)          if (*p != terminator)
           {            {
           *errorcodeptr = ERR57;            *errorcodeptr = ERR57;
Line 6501  for (;; ptr++) Line 6776  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. */
   
Line 6511  for (;; ptr++) Line 6786  for (;; ptr++)
         recno = -c - ESC_REF;          recno = -c - ESC_REF;
   
         HANDLE_REFERENCE:    /* Come here from named backref handling */          HANDLE_REFERENCE:    /* Come here from named backref handling */
        if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;        if (firstchar == REQ_UNSET) firstchar = 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 6578  for (;; ptr++) Line 6853  for (;; ptr++)
   
           {            {
           previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;            previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
          *code++ = (!utf8 && c == -ESC_C)? OP_ALLANY : -c;          *code++ = (!utf && c == -ESC_C)? OP_ALLANY : -c;
           }            }
         }          }
       continue;        continue;
Line 6588  for (;; ptr++) Line 6863  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#ifdef SUPPORT_UTF
    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 6611  for (;; ptr++) Line 6886  for (;; ptr++)
     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 6634  for (;; ptr++) Line 6906  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 (firstchar == REQ_UNSET)
       {        {
      zerofirstbyte = REQ_NONE;      zerofirstchar = REQ_NONE;
      zeroreqbyte = reqbyte;      zeroreqchar = reqchar;
   
      /* 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;        if (mclength != 1) reqchar = code[-1] | cd->req_varyopt;
         }          }
      else firstbyte = reqbyte = REQ_NONE;      else firstchar = reqchar = 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;      zeroreqchar = reqchar;
       if (mclength == 1 || req_caseopt == 0)        if (mclength == 1 || req_caseopt == 0)
        reqbyte = code[-1] | req_caseopt | cd->req_varyopt;        reqchar = code[-1] | req_caseopt | cd->req_varyopt;
       }        }
   
     break;            /* End of literal character handling */      break;            /* End of literal character handling */
Line 6701  Arguments: Line 6973  Arguments:
   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, or a negative number
  reqbyteptr     place to put the last required character, or a negative number  reqcharptr     place to put the last required character, or a negative number
   bcptr          pointer to the chain of currently open branches    bcptr          pointer to the chain of currently open branches
   cd             points to the data block with tables pointers etc.    cd             points to the data block with tables pointers etc.
   lengthptr      NULL during the real compile phase    lengthptr      NULL during the real compile phase
Line 6712  Returns:         TRUE on success Line 6984  Returns:         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, pcre_int32 *firstcharptr, pcre_int32 *reqcharptr,
  compile_data *cd, int *lengthptr)  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_int32 firstchar, reqchar;
int branchfirstbyte, branchreqbyte;pcre_int32 branchfirstchar, branchreqchar;
 int length;  int length;
 int orig_bracount;  int orig_bracount;
 int max_bracount;  int max_bracount;
Line 6734  branch_chain bc; Line 7006  branch_chain bc;
 bc.outer = bcptr;  bc.outer = bcptr;
 bc.current_branch = code;  bc.current_branch = code;
   
firstbyte = reqbyte = REQ_UNSET;firstchar = reqchar = 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 7065  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,        &branchreqchar, &bc, cond_depth, cd,
         (lengthptr == NULL)? NULL : &length))          (lengthptr == NULL)? NULL : &length))
     {      {
     *ptrptr = ptr;      *ptrptr = ptr;
Line 6810  for (;;) Line 7082  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;      reqchar = branchreqchar;
       }        }
   
    /* 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 (firstchar >= 0 && firstchar != branchfirstchar)
         {          {
        if (reqbyte < 0) reqbyte = firstbyte;        if (reqchar < 0) reqchar = firstchar;
        firstbyte = REQ_NONE;        firstchar = 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 (firstchar < 0 && branchfirstchar >= 0 && branchreqchar < 0)
          branchreqbyte = branchfirstbyte;          branchreqchar = branchfirstchar;
   
      /* Now ensure that the reqbytes match */      /* Now ensure that the reqchars match */
   
      if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))      if ((reqchar & ~REQ_VARY) != (branchreqchar & ~REQ_VARY))
        reqbyte = REQ_NONE;        reqchar = REQ_NONE;
      else reqbyte |= branchreqbyte;   /* To "or" REQ_VARY */      else reqchar |= branchreqchar;   /* 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 6916  for (;;) Line 7188  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 7208  for (;;)
   
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
    *firstbyteptr = firstbyte;    *firstcharptr = firstchar;
    *reqbyteptr = reqbyte;    *reqcharptr = reqchar;
     if (lengthptr != NULL)      if (lengthptr != NULL)
       {        {
       if (OFLOW_MAX - *lengthptr < length)        if (OFLOW_MAX - *lengthptr < length)
Line 7018  Returns:     TRUE or FALSE Line 7290  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)    unsigned int backref_map)
 {  {
 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 7095  Returns:         TRUE or FALSE Line 7367  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)    unsigned int backref_map)
 {  {
 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 7383  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:
Line 7198  Returns:     -1 or the fixed first char Line 7470  Returns:     -1 or the fixed first char
 */  */
   
 static int  static int
find_firstassertedchar(const uschar *code, BOOL inassert)find_firstassertedchar(const pcre_uchar *code, BOOL inassert)
 {  {
 register int c = -1;  register int c = -1;
 do {  do {
    int d;     int d;
    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,
      TRUE);
    register int op = *scode;     register int op = *scode;
   
    switch(op)     switch(op)
Line 7229  do { Line 7502  do {
      break;       break;
   
      case OP_EXACT:       case OP_EXACT:
     scode += 2;     scode += IMM2_SIZE;
      /* Fall through */       /* Fall through */
   
      case OP_CHAR:       case OP_CHAR:
Line 7242  do { Line 7515  do {
      break;       break;
   
      case OP_EXACTI:       case OP_EXACTI:
     scode += 2;     scode += IMM2_SIZE;
      /* Fall through */       /* Fall through */
   
      case OP_CHARI:       case OP_CHARI:
Line 7285  Returns:        pointer to compiled data block, or NUL Line 7558  Returns:        pointer to compiled data block, or NUL
                 with errorptr and erroroffset set                  with errorptr and erroroffset set
 */  */
   
   #ifdef 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)
   #else
   PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
   pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr,
     int *erroroffset, const unsigned char *tables)
   #endif
 {  {
   #ifdef COMPILE_PCRE8
 return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);  return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #else
   return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #endif
 }  }
   
   
   #ifdef 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)
   #else
   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)
   #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 firstchar, reqchar;
 int newline;
 int errorcode = 0;  int errorcode = 0;
 int skipatstart = 0;  int skipatstart = 0;
BOOL utf8;BOOL utf;
 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 7607  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];
   
 /* 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 7638  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 7371  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && Line 7661  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
   int newnl = 0;    int newnl = 0;
   int newbsr = 0;    int newbsr = 0;
   
  if (strncmp((char *)(ptr+skipatstart+2), STRING_UTF8_RIGHTPAR, 5) == 0)#ifdef COMPILE_PCRE8
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_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_UTF_RIGHTPAR, 6) == 0)
     { skipatstart += 8; options |= PCRE_UTF16; continue; }
 #endif
   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_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)  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 7697  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
   else break;    else break;
   }    }
   
utf8 = (options & PCRE_UTF8) != 0;/* PCRE_UTF16 has the same value as PCRE_UTF8. */
 utf = (options & PCRE_UTF8) != 0;
   
/* 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)
   {    {
   #ifdef COMPILE_PCRE8
   errorcode = ERR44;    errorcode = ERR44;
   #else
     errorcode = ERR74;
   #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 7793  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 7509  cd->start_code = cworkspace; Line 7813  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->start_pattern = (const pcre_uchar *)pattern;
cd->end_pattern = (const uschar *)(pattern + strlen(pattern));cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern));
 cd->req_varyopt = 0;  cd->req_varyopt = 0;
   cd->assert_depth = 0;
 cd->external_options = options;  cd->external_options = options;
 cd->external_flags = 0;  cd->external_flags = 0;
 cd->open_caps = NULL;  cd->open_caps = NULL;
Line 7526  ptr += skipatstart; Line 7831  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, &reqchar, 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 7543  externally provided function. Integer overflow should  Line 7848  externally provided function. Integer overflow should 
 because nowadays we limit the maximum value of cd->names_found and  because nowadays we limit the maximum value of cd->names_found and
 cd->name_entry_size. */  cd->name_entry_size. */
   
size = length + sizeof(real_pcre) + cd->names_found * cd->name_entry_size;size = sizeof(REAL_PCRE) + (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar);
re = (real_pcre *)(pcre_malloc)(size);re = (REAL_PCRE *)(PUBL(malloc))(size);
   
 if (re == NULL)  if (re == NULL)
   {    {
Line 7563  re->size = (int)size; Line 7868  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->dummy1 = 0;
re->first_byte = 0;re->first_char = 0;
re->req_byte = 0;re->req_char = 0;
re->name_table_offset = sizeof(real_pcre);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;
   
 /* 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
Line 7583  cd->final_bracount = cd->bracount;  /* Save for checki Line 7888  cd->final_bracount = cd->bracount;  /* Save for checki
 cd->assert_depth = 0;  cd->assert_depth = 0;
 cd->bracount = 0;  cd->bracount = 0;
 cd->names_found = 0;  cd->names_found = 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->check_lookbehind = FALSE;  cd->check_lookbehind = FALSE;
Line 7596  cd->open_caps = NULL; Line 7901  cd->open_caps = NULL;
 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, &reqchar, 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->flags = cd->external_flags | PCRE_MODE;
   
if (cd->had_accept) reqbyte = REQ_NONE;   /* Must disable after (*ACCEPT) */if (cd->had_accept) reqchar = REQ_NONE;   /* Must disable after (*ACCEPT) */
   
 /* 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. */
   
Line 7626  references; optimize for them, as searching a large re Line 7931  references; optimize for them, as searching a large re
 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 7940  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. */
   
 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);
   
 /* 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. */
Line 7663  length, and set their lengths. */ Line 7968  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 7700  if (cd->check_lookbehind) Line 8005  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 7725  if ((re->options & PCRE_ANCHORED) == 0) Line 8030  if ((re->options & PCRE_ANCHORED) == 0)
     re->options |= PCRE_ANCHORED;      re->options |= PCRE_ANCHORED;
   else    else
     {      {
    if (firstbyte < 0)    if (firstchar < 0)
      firstbyte = find_firstassertedchar(codestart, FALSE);      firstchar = find_firstassertedchar(codestart, FALSE);
    if (firstbyte >= 0)   /* Remove caseless flag for non-caseable chars */    if (firstchar >= 0)   /* Remove caseless flag for non-caseable chars */
       {        {
      int ch = firstbyte & 255;#ifdef COMPILE_PCRE8
      re->first_byte = ((firstbyte & REQ_CASELESS) != 0 &&      re->first_char = firstchar & 0xff;
         cd->fcc[ch] == ch)? ch : firstbyte;#else
 #ifdef COMPILE_PCRE16
       re->first_char = firstchar & 0xffff;
 #endif
 #endif
       if ((firstchar & 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))      else if (is_startline(codestart, 0, cd->backref_map))
Line 7743  if ((re->options & PCRE_ANCHORED) == 0) Line 8073  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 (reqchar >= 0 &&
     ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0))     ((re->options & PCRE_ANCHORED) == 0 || (reqchar & REQ_VARY) != 0))
   {    {
  int ch = reqbyte & 255;#ifdef COMPILE_PCRE8
  re->req_byte = ((reqbyte & REQ_CASELESS) != 0 &&  re->req_char = reqchar & 0xff;
    cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;#else
 #ifdef COMPILE_PCRE16
   re->req_char = reqchar & 0xffff;
 #endif
 #endif
   if ((reqchar & 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 8117  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);#ifdef COMPILE_PCRE8
 pcre_printint((pcre *)re, stdout, TRUE);
 #else
 pcre16_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 */
   
   #ifdef COMPILE_PCRE8
 return (pcre *)re;  return (pcre *)re;
   #else
   return (pcre16 *)re;
   #endif
 }  }
   
 /* End of pcre_compile.c */  /* End of pcre_compile.c */

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


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