Diff for /embedaddon/pcre/pcre_compile.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2012/10/09 09:19:17 version 1.1.1.4, 2013/07/22 08:25:55
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-2012 University of Cambridge           Copyright (c) 1997-2013 University of Cambridge
   
 -----------------------------------------------------------------------------  -----------------------------------------------------------------------------
 Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
Line 53  supporting internal functions that are not used by oth Line 53  supporting internal functions that are not used by oth
 #include "pcre_internal.h"  #include "pcre_internal.h"
   
   
/* When PCRE_DEBUG is defined, we need the pcre(16)_printint() function, which/* When PCRE_DEBUG is defined, we need the pcre(16|32)_printint() function, which
 is also used by pcretest. PCRE_DEBUG is not defined when building a production  is also used by pcretest. PCRE_DEBUG is not defined when building a production
 library. We do not need to select pcre16_printint.c specially, because the  library. We do not need to select pcre16_printint.c specially, because the
 COMPILE_PCREx macro will already be appropriately set. */  COMPILE_PCREx macro will already be appropriately set. */
Line 68  COMPILE_PCREx macro will already be appropriately set. Line 68  COMPILE_PCREx macro will already be appropriately set.
   
 /* Macro for setting individual bits in class bitmaps. */  /* Macro for setting individual bits in class bitmaps. */
   
#define SETBIT(a,b) a[b/8] |= (1 << (b%8))#define SETBIT(a,b) a[(b)/8] |= (1 << ((b)&7))
   
 /* Maximum length value to check against when making sure that the integer that  /* Maximum length value to check against when making sure that the integer that
 holds the compiled pattern length does not overflow. We make it a bit less than  holds the compiled pattern length does not overflow. We make it a bit less than
Line 77  to check them every time. */ Line 77  to check them every time. */
   
 #define OFLOW_MAX (INT_MAX - 20)  #define OFLOW_MAX (INT_MAX - 20)
   
   /* Definitions to allow mutual recursion */
   
   static int
     add_list_to_class(pcre_uint8 *, pcre_uchar **, int, compile_data *,
       const pcre_uint32 *, unsigned int);
   
   static BOOL
     compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int,
       pcre_uint32 *, pcre_int32 *, pcre_uint32 *, pcre_int32 *, branch_chain *,
       compile_data *, int *);
   
   
   
 /*************************************************  /*************************************************
 *      Code parameters and static tables         *  *      Code parameters and static tables         *
 *************************************************/  *************************************************/
Line 110  overrun before it actually does run off the end of the Line 122  overrun before it actually does run off the end of the
   
 /* Private flags added to firstchar and reqchar. */  /* Private flags added to firstchar and reqchar. */
   
#define REQ_CASELESS   0x10000000l      /* Indicates caselessness */#define REQ_CASELESS    (1 << 0)        /* Indicates caselessness */
#define REQ_VARY       0x20000000l      /* Reqchar followed non-literal item */#define REQ_VARY        (1 << 1)        /* Reqchar followed non-literal item */
 /* Negative values for the firstchar and reqchar flags */
 #define REQ_UNSET       (-2)
 #define REQ_NONE        (-1)
   
 /* Repeated character flags. */  /* Repeated character flags. */
   
Line 472  static const char error_texts[] = Line 487  static const char error_texts[] =
   "a numbered reference must not be zero\0"    "a numbered reference must not be zero\0"
   "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"    "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"
   /* 60 */    /* 60 */
  "(*VERB) not recognized\0"  "(*VERB) not recognized or malformed\0"
   "number is too big\0"    "number is too big\0"
   "subpattern name expected\0"    "subpattern name expected\0"
   "digit expected after (?+\0"    "digit expected after (?+\0"
Line 492  static const char error_texts[] = Line 507  static const char error_texts[] =
   /* 75 */    /* 75 */
   "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"    "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
   "character value in \\u.... sequence is too large\0"    "character value in \\u.... sequence is too large\0"
     "invalid UTF-32 string\0"
     "setting UTF is disabled by the application\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 631  static const pcre_uint8 ebcdic_chartab[] = { /* charta Line 648  static const pcre_uint8 ebcdic_chartab[] = { /* charta
 #endif  #endif
   
   
 /* Definition to allow mutual recursion */  
   
 static BOOL  
   compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int,  
     int *, int *, branch_chain *, compile_data *, int *);  
   
   
   
 /*************************************************  /*************************************************
 *            Find an error text                  *  *            Find an error text                  *
 *************************************************/  *************************************************/
Line 658  find_error_text(int n) Line 668  find_error_text(int n)
 const char *s = error_texts;  const char *s = error_texts;
 for (; n > 0; n--)  for (; n > 0; n--)
   {    {
  while (*s++ != 0) {};  while (*s++ != CHAR_NULL) {};
  if (*s == 0) return "Error text not found (please report)";  if (*s == CHAR_NULL) return "Error text not found (please report)";
   }    }
 return s;  return s;
 }  }
Line 742  return (*p == CHAR_RIGHT_CURLY_BRACKET); Line 752  return (*p == CHAR_RIGHT_CURLY_BRACKET);
 *************************************************/  *************************************************/
   
 /* This function is called when a \ has been encountered. It either returns a  /* This function is called when a \ has been encountered. It either returns a
positive value for a simple escape such as \n, or a negative value whichpositive value for a simple escape such as \n, or 0 for a data character
encodes one of the more complicated things such as \d. A backreference to groupwhich will be placed in chptr. A backreference to group n is returned as
n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. Whennegative n. When UTF-8 is enabled, a positive value greater than 255 may
UTF-8 is enabled, a positive value greater than 255 may be returned. On entry,be returned in chptr.
ptr is pointing at the \. On exit, it is on the final character of the escapeOn entry,ptr is pointing at the \. On exit, it is on the final character of the
sequence.escape sequence.
   
 Arguments:  Arguments:
   ptrptr         points to the pattern position pointer    ptrptr         points to the pattern position pointer
     chptr          points to the data character
   errorcodeptr   points to the errorcode variable    errorcodeptr   points to the errorcode variable
   bracount       number of previous extracting brackets    bracount       number of previous extracting brackets
   options        the options bits    options        the options bits
   isclass        TRUE if inside a character class    isclass        TRUE if inside a character class
   
Returns:         zero or positive => a data characterReturns:         zero => a data character
                 negative => a special escape sequence                 positive => a special escape sequence
                  negative => a back reference
                  on error, errorcodeptr is set                   on error, errorcodeptr is set
 */  */
   
 static int  static int
check_escape(const pcre_uchar **ptrptr, int *errorcodeptr, int bracount,check_escape(const pcre_uchar **ptrptr, pcre_uint32 *chptr, int *errorcodeptr,
  int options, BOOL isclass)  int bracount, int options, BOOL isclass)
 {  {
 /* PCRE_UTF16 has the same value as PCRE_UTF8. */  /* PCRE_UTF16 has the same value as PCRE_UTF8. */
 BOOL utf = (options & PCRE_UTF8) != 0;  BOOL utf = (options & PCRE_UTF8) != 0;
 const pcre_uchar *ptr = *ptrptr + 1;  const pcre_uchar *ptr = *ptrptr + 1;
pcre_int32 c;pcre_uint32 c;
 int escape = 0;
 int i;  int i;
   
 GETCHARINCTEST(c, ptr);           /* Get character value, increment pointer */  GETCHARINCTEST(c, ptr);           /* Get character value, increment pointer */
Line 776  ptr--;                            /* Set pointer back  Line 789  ptr--;                            /* Set pointer back 
   
 /* If backslash is at the end of the pattern, it's an error. */  /* If backslash is at the end of the pattern, it's an error. */
   
if (c == 0) *errorcodeptr = ERR1;if (c == CHAR_NULL) *errorcodeptr = ERR1;
   
 /* Non-alphanumerics are literals. For digits or letters, do an initial lookup  /* Non-alphanumerics are literals. For digits or letters, do an initial lookup
 in a table. A non-zero result is something that can be returned immediately.  in a table. A non-zero result is something that can be returned immediately.
Line 785  Otherwise further processing may be required. */ Line 798  Otherwise further processing may be required. */
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
 /* Not alphanumeric */  /* Not alphanumeric */
 else if (c < CHAR_0 || c > CHAR_z) {}  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)
   { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
   
 #else           /* EBCDIC coding */  #else           /* EBCDIC coding */
 /* Not alphanumeric */  /* Not alphanumeric */
else if (c < 'a' || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {}else if (c < CHAR_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)  { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
 #endif  #endif
   
 /* Escapes that need further processing, or are illegal. */  /* Escapes that need further processing, or are illegal. */
Line 798  else if ((i = escapes[c - 0x48]) != 0)  c = i; Line 812  else if ((i = escapes[c - 0x48]) != 0)  c = i;
 else  else
   {    {
   const pcre_uchar *oldptr;    const pcre_uchar *oldptr;
  BOOL braced, negated;  BOOL braced, negated, overflow;
   int s;
   
   switch (c)    switch (c)
     {      {
Line 823  else Line 838  else
         c = 0;          c = 0;
         for (i = 0; i < 4; ++i)          for (i = 0; i < 4; ++i)
           {            {
          register int cc = *(++ptr);          register pcre_uint32 cc = *(++ptr);
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
           if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */            if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
           c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));            c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
Line 833  else Line 848  else
 #endif  #endif
           }            }
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
        if (c > (utf ? 0x10ffff : 0xff))        if (c > (utf ? 0x10ffffU : 0xffU))
#else#elif defined COMPILE_PCRE16
#ifdef COMPILE_PCRE16        if (c > (utf ? 0x10ffffU : 0xffffU))
        if (c > (utf ? 0x10ffff : 0xffff))#elif defined COMPILE_PCRE32
         if (utf && c > 0x10ffffU)
 #endif  #endif
 #endif  
           {            {
           *errorcodeptr = ERR76;            *errorcodeptr = ERR76;
           }            }
Line 870  else Line 885  else
     (3) For Oniguruma compatibility we also support \g followed by a name or a      (3) For Oniguruma compatibility we also support \g followed by a name or a
     number either in angle brackets or in single quotes. However, these are      number either in angle brackets or in single quotes. However, these are
     (possibly recursive) subroutine calls, _not_ backreferences. Just return      (possibly recursive) subroutine calls, _not_ backreferences. Just return
    the -ESC_g code (cf \k). */    the ESC_g code (cf \k). */
   
     case CHAR_g:      case CHAR_g:
     if (isclass) break;      if (isclass) break;
     if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)      if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)
       {        {
      c = -ESC_g;      escape = ESC_g;
       break;        break;
       }        }
   
Line 885  else Line 900  else
     if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)      if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
       {        {
       const pcre_uchar *p;        const pcre_uchar *p;
      for (p = ptr+2; *p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET; p++)      for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++)
         if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;          if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;
      if (*p != 0 && *p != CHAR_RIGHT_CURLY_BRACKET)      if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET)
         {          {
        c = -ESC_k;        escape = ESC_k;
         break;          break;
         }          }
       braced = TRUE;        braced = TRUE;
Line 905  else Line 920  else
     else negated = FALSE;      else negated = FALSE;
   
     /* The integer range is limited by the machine's int representation. */      /* The integer range is limited by the machine's int representation. */
    c = 0;    s = 0;
     overflow = FALSE;
     while (IS_DIGIT(ptr[1]))      while (IS_DIGIT(ptr[1]))
       {        {
      if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */      if (s > INT_MAX / 10 - 1) /* Integer overflow */
         {          {
        c = -1;        overflow = TRUE;
         break;          break;
         }          }
      c = c * 10 + *(++ptr) - CHAR_0;      s = s * 10 + (int)(*(++ptr) - CHAR_0);
       }        }
    if (((unsigned int)c) > INT_MAX) /* Integer overflow */    if (overflow) /* Integer overflow */
       {        {
       while (IS_DIGIT(ptr[1]))        while (IS_DIGIT(ptr[1]))
         ptr++;          ptr++;
Line 929  else Line 945  else
       break;        break;
       }        }
   
    if (c == 0)    if (s == 0)
       {        {
       *errorcodeptr = ERR58;        *errorcodeptr = ERR58;
       break;        break;
Line 937  else Line 953  else
   
     if (negated)      if (negated)
       {        {
      if (c > bracount)      if (s > bracount)
         {          {
         *errorcodeptr = ERR15;          *errorcodeptr = ERR15;
         break;          break;
         }          }
      c = bracount - (c - 1);      s = bracount - (s - 1);
       }        }
   
    c = -(ESC_REF + c);    escape = -s;
     break;      break;
   
     /* The handling of escape sequences consisting of a string of digits      /* The handling of escape sequences consisting of a string of digits
Line 967  else Line 983  else
       {        {
       oldptr = ptr;        oldptr = ptr;
       /* The integer range is limited by the machine's int representation. */        /* The integer range is limited by the machine's int representation. */
      c -= CHAR_0;      s = (int)(c -CHAR_0);
       overflow = FALSE;
       while (IS_DIGIT(ptr[1]))        while (IS_DIGIT(ptr[1]))
         {          {
        if (((unsigned int)c) > INT_MAX / 10) /* Integer overflow */        if (s > INT_MAX / 10 - 1) /* Integer overflow */
           {            {
          c = -1;          overflow = TRUE;
           break;            break;
           }            }
        c = c * 10 + *(++ptr) - CHAR_0;        s = s * 10 + (int)(*(++ptr) - CHAR_0);
         }          }
      if (((unsigned int)c) > INT_MAX) /* Integer overflow */      if (overflow) /* Integer overflow */
         {          {
         while (IS_DIGIT(ptr[1]))          while (IS_DIGIT(ptr[1]))
           ptr++;            ptr++;
         *errorcodeptr = ERR61;          *errorcodeptr = ERR61;
         break;          break;
         }          }
      if (c < 10 || c <= bracount)      if (s < 10 || s <= bracount)
         {          {
        c = -(ESC_REF + c);        escape = -s;
         break;          break;
         }          }
       ptr = oldptr;      /* Put the pointer back and fall through */        ptr = oldptr;      /* Put the pointer back and fall through */
Line 1033  else Line 1050  else
         c = 0;          c = 0;
         for (i = 0; i < 2; ++i)          for (i = 0; i < 2; ++i)
           {            {
          register int cc = *(++ptr);          register pcre_uint32 cc = *(++ptr);
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
           if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */            if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
           c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));            c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
Line 1051  else Line 1068  else
       const pcre_uchar *pt = ptr + 2;        const pcre_uchar *pt = ptr + 2;
   
       c = 0;        c = 0;
         overflow = FALSE;
       while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0)        while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0)
         {          {
        register int cc = *pt++;        register pcre_uint32 cc = *pt++;
         if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */          if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
   
   #ifdef COMPILE_PCRE32
           if (c >= 0x10000000l) { overflow = TRUE; break; }
   #endif
   
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
         if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */          if (cc >= CHAR_a) cc -= 32;               /* Convert to upper case */
         c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));          c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
Line 1064  else Line 1086  else
         c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));          c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
 #endif  #endif
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
        if (c > (utf ? 0x10ffff : 0xff)) { c = -1; break; }        if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
#else#elif defined COMPILE_PCRE16
#ifdef COMPILE_PCRE16        if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
        if (c > (utf ? 0x10ffff : 0xffff)) { c = -1; break; }#elif defined COMPILE_PCRE32
         if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
 #endif  #endif
 #endif  
         }          }
   
      if (c < 0)      if (overflow)
         {          {
         while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0) pt++;          while (MAX_255(*pt) && (digitab[*pt] & ctype_xdigit) != 0) pt++;
         *errorcodeptr = ERR34;          *errorcodeptr = ERR34;
Line 1095  else Line 1117  else
     c = 0;      c = 0;
     while (i++ < 2 && MAX_255(ptr[1]) && (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 */      pcre_uint32 cc;                          /* Some compilers don't like */
       cc = *(++ptr);                           /* ++ in initializers */        cc = *(++ptr);                           /* ++ in initializers */
 #ifndef EBCDIC  /* ASCII/UTF-8 coding */  #ifndef EBCDIC  /* ASCII/UTF-8 coding */
       if (cc >= CHAR_a) cc -= 32;              /* Convert to upper case */        if (cc >= CHAR_a) cc -= 32;              /* Convert to upper case */
Line 1114  else Line 1136  else
   
     case CHAR_c:      case CHAR_c:
     c = *(++ptr);      c = *(++ptr);
    if (c == 0)    if (c == CHAR_NULL)
       {        {
       *errorcodeptr = ERR2;        *errorcodeptr = ERR2;
       break;        break;
Line 1154  else Line 1176  else
 newline". PCRE does not support \N{name}. However, it does support  newline". PCRE does not support \N{name}. However, it does support
 quantification such as \N{2,3}. */  quantification such as \N{2,3}. */
   
if (c == -ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&
      !is_counted_repeat(ptr+2))       !is_counted_repeat(ptr+2))
   *errorcodeptr = ERR37;    *errorcodeptr = ERR37;
   
 /* If PCRE_UCP is set, we change the values for \d etc. */  /* If PCRE_UCP is set, we change the values for \d etc. */
   
if ((options & PCRE_UCP) != 0 && c <= -ESC_D && c >= -ESC_w)if ((options & PCRE_UCP) != 0 && escape >= ESC_D && escape <= ESC_w)
  c -= (ESC_DU - ESC_D);  escape += (ESC_DU - ESC_D);
   
 /* Set the pointer to the final character before returning. */  /* Set the pointer to the final character before returning. */
   
 *ptrptr = ptr;  *ptrptr = ptr;
return c;*chptr = c;
 return escape;
 }  }
   
   
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
 /*************************************************  /*************************************************
 *               Handle \P and \p                 *  *               Handle \P and \p                 *
Line 1184  escape sequence. Line 1205  escape sequence.
 Argument:  Argument:
   ptrptr         points to the pattern position pointer    ptrptr         points to the pattern position pointer
   negptr         points to a boolean that is set TRUE for negation else FALSE    negptr         points to a boolean that is set TRUE for negation else FALSE
  dptr           points to an int that is set to the detailed property value  ptypeptr       points to an unsigned int that is set to the type value
   pdataptr       points to an unsigned int that is set to the detailed property value
   errorcodeptr   points to the error code variable    errorcodeptr   points to the error code variable
   
Returns:         type value from ucp_type_table, or -1 for an invalid typeReturns:         TRUE if the type value was found, or FALSE for an invalid type
 */  */
   
static intstatic BOOL
get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr)get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, unsigned int *ptypeptr,
   unsigned int *pdataptr, int *errorcodeptr)
 {  {
int c, i, bot, top;pcre_uchar c;
 int i, bot, top;
 const pcre_uchar *ptr = *ptrptr;  const pcre_uchar *ptr = *ptrptr;
 pcre_uchar name[32];  pcre_uchar name[32];
   
 c = *(++ptr);  c = *(++ptr);
if (c == 0) goto ERROR_RETURN;if (c == CHAR_NULL) goto ERROR_RETURN;
   
 *negptr = FALSE;  *negptr = FALSE;
   
Line 1215  if (c == CHAR_LEFT_CURLY_BRACKET) Line 1239  if (c == CHAR_LEFT_CURLY_BRACKET)
   for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++)    for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++)
     {      {
     c = *(++ptr);      c = *(++ptr);
    if (c == 0) goto ERROR_RETURN;    if (c == CHAR_NULL) goto ERROR_RETURN;
     if (c == CHAR_RIGHT_CURLY_BRACKET) break;      if (c == CHAR_RIGHT_CURLY_BRACKET) break;
     name[i] = c;      name[i] = c;
     }      }
Line 1240  top = PRIV(utt_size); Line 1264  top = PRIV(utt_size);
   
 while (bot < top)  while (bot < top)
   {    {
     int r;
   i = (bot + top) >> 1;    i = (bot + top) >> 1;
  c = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);  r = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
  if (c == 0)  if (r == 0)
     {      {
    *dptr = PRIV(utt)[i].value;    *ptypeptr = PRIV(utt)[i].type;
    return PRIV(utt)[i].type;    *pdataptr = PRIV(utt)[i].value;
     return TRUE;
     }      }
  if (c > 0) bot = i + 1; else top = i;  if (r > 0) bot = i + 1; else top = i;
   }    }
   
 *errorcodeptr = ERR47;  *errorcodeptr = ERR47;
 *ptrptr = ptr;  *ptrptr = ptr;
return -1;return FALSE;
   
 ERROR_RETURN:  ERROR_RETURN:
 *errorcodeptr = ERR46;  *errorcodeptr = ERR46;
 *ptrptr = ptr;  *ptrptr = ptr;
return -1;return FALSE;
 }  }
 #endif  #endif
   
Line 1292  int max = -1; Line 1318  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 (IS_DIGIT(*p)) min = min * 10 + *p++ - CHAR_0;while (IS_DIGIT(*p)) min = min * 10 + (int)(*p++ - CHAR_0);
 if (min < 0 || min > 65535)  if (min < 0 || min > 65535)
   {    {
   *errorcodeptr = ERR5;    *errorcodeptr = ERR5;
Line 1307  if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else Line 1333  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(IS_DIGIT(*p)) max = max * 10 + *p++ - CHAR_0;    while(IS_DIGIT(*p)) max = max * 10 + (int)(*p++ - CHAR_0);
     if (max < 0 || max > 65535)      if (max < 0 || max > 65535)
       {        {
       *errorcodeptr = ERR5;        *errorcodeptr = ERR5;
Line 1362  Arguments: Line 1388  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
  utf          TRUE if we are in UTF-8 / UTF-16 mode  utf          TRUE if we are in UTF-8 / UTF-16 / UTF-32 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
Line 1384  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1410  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
   {    {
   /* Handle specials such as (*SKIP) or (*UTF8) etc. */    /* Handle specials such as (*SKIP) or (*UTF8) etc. */
   
  if (ptr[1] == CHAR_ASTERISK) ptr += 2;  if (ptr[1] == CHAR_ASTERISK)
     {
     ptr += 2;
     while (ptr < cd->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
     }
   
   /* Handle a normal, unnamed capturing parenthesis. */    /* Handle a normal, unnamed capturing parenthesis. */
   
Line 1408  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1438  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
   
   else if (ptr[2] == CHAR_NUMBER_SIGN)    else if (ptr[2] == CHAR_NUMBER_SIGN)
     {      {
    for (ptr += 3; *ptr != 0; ptr++) if (*ptr == CHAR_RIGHT_PARENTHESIS) break;    for (ptr += 3; *ptr != CHAR_NULL; ptr++)
       if (*ptr == CHAR_RIGHT_PARENTHESIS) break;
     goto FAIL_EXIT;      goto FAIL_EXIT;
     }      }
   
Line 1421  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1452  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
     ptr += 2;      ptr += 2;
     if (ptr[1] != CHAR_QUESTION_MARK)      if (ptr[1] != CHAR_QUESTION_MARK)
       {        {
      while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;      while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
      if (*ptr != 0) ptr++;      if (*ptr != CHAR_NULL) ptr++;
       }        }
     }      }
   
Line 1438  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1469  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
     if ((*ptr == CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK &&      if ((*ptr == CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK &&
         ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE)          ptr[1] != CHAR_EQUALS_SIGN) || *ptr == CHAR_APOSTROPHE)
       {        {
      int term;      pcre_uchar term;
       const pcre_uchar *thisname;        const pcre_uchar *thisname;
       *count += 1;        *count += 1;
       if (name == NULL && *count == lorn) return *count;        if (name == NULL && *count == lorn) return *count;
Line 1446  if (ptr[0] == CHAR_LEFT_PARENTHESIS) Line 1477  if (ptr[0] == CHAR_LEFT_PARENTHESIS)
       if (term == CHAR_LESS_THAN_SIGN) term = CHAR_GREATER_THAN_SIGN;        if (term == CHAR_LESS_THAN_SIGN) term = CHAR_GREATER_THAN_SIGN;
       thisname = ptr;        thisname = ptr;
       while (*ptr != term) ptr++;        while (*ptr != term) ptr++;
      if (name != NULL && lorn == ptr - thisname &&      if (name != NULL && lorn == (int)(ptr - thisname) &&
          STRNCMP_UC_UC(name, thisname, lorn) == 0)          STRNCMP_UC_UC(name, thisname, (unsigned int)lorn) == 0)
         return *count;          return *count;
       term++;        term++;
       }        }
Line 1465  for (; ptr < cd->end_pattern; ptr++) Line 1496  for (; ptr < cd->end_pattern; ptr++)
   
   if (*ptr == CHAR_BACKSLASH)    if (*ptr == CHAR_BACKSLASH)
     {      {
    if (*(++ptr) == 0) goto FAIL_EXIT;    if (*(++ptr) == CHAR_NULL) goto FAIL_EXIT;
     if (*ptr == CHAR_Q) for (;;)      if (*ptr == CHAR_Q) for (;;)
       {        {
      while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {};      while (*(++ptr) != CHAR_NULL && *ptr != CHAR_BACKSLASH) {};
      if (*ptr == 0) goto FAIL_EXIT;      if (*ptr == CHAR_NULL) goto FAIL_EXIT;
       if (*(++ptr) == CHAR_E) break;        if (*(++ptr) == CHAR_E) break;
       }        }
     continue;      continue;
Line 1513  for (; ptr < cd->end_pattern; ptr++) Line 1544  for (; ptr < cd->end_pattern; ptr++)
   
     while (*(++ptr) != CHAR_RIGHT_SQUARE_BRACKET)      while (*(++ptr) != CHAR_RIGHT_SQUARE_BRACKET)
       {        {
      if (*ptr == 0) return -1;      if (*ptr == CHAR_NULL) return -1;
       if (*ptr == CHAR_BACKSLASH)        if (*ptr == CHAR_BACKSLASH)
         {          {
        if (*(++ptr) == 0) goto FAIL_EXIT;        if (*(++ptr) == CHAR_NULL) goto FAIL_EXIT;
         if (*ptr == CHAR_Q) for (;;)          if (*ptr == CHAR_Q) for (;;)
           {            {
          while (*(++ptr) != 0 && *ptr != CHAR_BACKSLASH) {};          while (*(++ptr) != CHAR_NULL && *ptr != CHAR_BACKSLASH) {};
          if (*ptr == 0) goto FAIL_EXIT;          if (*ptr == CHAR_NULL) goto FAIL_EXIT;
           if (*(++ptr) == CHAR_E) break;            if (*(++ptr) == CHAR_E) break;
           }            }
         continue;          continue;
Line 1534  for (; ptr < cd->end_pattern; ptr++) Line 1565  for (; ptr < cd->end_pattern; ptr++)
   if (xmode && *ptr == CHAR_NUMBER_SIGN)    if (xmode && *ptr == CHAR_NUMBER_SIGN)
     {      {
     ptr++;      ptr++;
    while (*ptr != 0)    while (*ptr != CHAR_NULL)
       {        {
       if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }        if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }
       ptr++;        ptr++;
Line 1542  for (; ptr < cd->end_pattern; ptr++) Line 1573  for (; ptr < cd->end_pattern; ptr++)
       if (utf) FORWARDCHAR(ptr);        if (utf) FORWARDCHAR(ptr);
 #endif  #endif
       }        }
    if (*ptr == 0) goto FAIL_EXIT;    if (*ptr == CHAR_NULL) goto FAIL_EXIT;
     continue;      continue;
     }      }
   
Line 1552  for (; ptr < cd->end_pattern; ptr++) Line 1583  for (; ptr < cd->end_pattern; ptr++)
     {      {
     int rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, 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 == CHAR_NULL) goto FAIL_EXIT;
     }      }
   
   else if (*ptr == CHAR_RIGHT_PARENTHESIS)    else if (*ptr == CHAR_RIGHT_PARENTHESIS)
Line 1596  Arguments: Line 1627  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
  utf          TRUE if we are in UTF-8 / UTF-16 mode  utf          TRUE if we are in UTF-8 / UTF-16 / UTF-32 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
 */  */
Line 1617  matching closing parens. That is why we have to have a Line 1648  matching closing parens. That is why we have to have a
 for (;;)  for (;;)
   {    {
   rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, &count);    rc = find_parens_sub(&ptr, cd, name, lorn, xmode, utf, &count);
  if (rc > 0 || *ptr++ == 0) break;  if (rc > 0 || *ptr++ == CHAR_NULL) break;
   }    }
   
 return rc;  return rc;
Line 1699  and doing the check at the end; a flag specifies which Line 1730  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)
  utf      TRUE in UTF-8 / UTF-16 mode  utf      TRUE in UTF-8 / UTF-16 / UTF-32 mode
   atend    TRUE if called when the pattern is complete    atend    TRUE if called when the pattern is complete
   cd       the "compile data" structure    cd       the "compile data" structure
   
Line 1725  for (;;) Line 1756  for (;;)
   {    {
   int d;    int d;
   pcre_uchar *ce, *cs;    pcre_uchar *ce, *cs;
  register int op = *cc;  register pcre_uchar op = *cc;
   
   switch (op)    switch (op)
     {      {
Line 1845  for (;;) Line 1876  for (;;)
     case OP_EXACTI:      case OP_EXACTI:
     case OP_NOTEXACT:      case OP_NOTEXACT:
     case OP_NOTEXACTI:      case OP_NOTEXACTI:
    branchlength += GET2(cc,1);    branchlength += (int)GET2(cc,1);
     cc += 2 + IMM2_SIZE;      cc += 2 + IMM2_SIZE;
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
     if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);      if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
Line 1854  for (;;) Line 1885  for (;;)
   
     case OP_TYPEEXACT:      case OP_TYPEEXACT:
     branchlength += GET2(cc,1);      branchlength += GET2(cc,1);
    if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2;    if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP)
       cc += 2;
     cc += 1 + IMM2_SIZE + 1;      cc += 1 + IMM2_SIZE + 1;
     break;      break;
   
Line 1889  for (;;) Line 1921  for (;;)
   
     /* Check a class for variable quantification */      /* Check a class for variable quantification */
   
 #if defined SUPPORT_UTF || defined COMPILE_PCRE16  
     case OP_XCLASS:  
     cc += GET(cc, 1) - PRIV(OP_lengths)[OP_CLASS];  
     /* Fall through */  
 #endif  
   
     case OP_CLASS:      case OP_CLASS:
     case OP_NCLASS:      case OP_NCLASS:
   #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
       case OP_XCLASS:
       /* The original code caused an unsigned overflow in 64 bit systems,
       so now we use a conditional statement. */
       if (op == OP_XCLASS)
         cc += GET(cc, 1);
       else
         cc += PRIV(OP_lengths)[OP_CLASS];
   #else
     cc += PRIV(OP_lengths)[OP_CLASS];      cc += PRIV(OP_lengths)[OP_CLASS];
   #endif
   
     switch (*cc)      switch (*cc)
       {        {
Line 1912  for (;;) Line 1948  for (;;)
       case OP_CRRANGE:        case OP_CRRANGE:
       case OP_CRMINRANGE:        case OP_CRMINRANGE:
       if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1;        if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1;
      branchlength += GET2(cc,1);      branchlength += (int)GET2(cc,1);
       cc += 1 + 2 * IMM2_SIZE;        cc += 1 + 2 * IMM2_SIZE;
       break;        break;
   
Line 2028  length. Line 2064  length.
   
 Arguments:  Arguments:
   code        points to start of expression    code        points to start of expression
  utf         TRUE in UTF-8 / UTF-16 mode  utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
   number      the required bracket number or negative to find a lookbehind    number      the required bracket number or negative to find a lookbehind
   
 Returns:      pointer to the opcode for the bracket, or NULL if not found  Returns:      pointer to the opcode for the bracket, or NULL if not found
Line 2039  PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, i Line 2075  PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, i
 {  {
 for (;;)  for (;;)
   {    {
  register int c = *code;  register pcre_uchar c = *code;
   
   if (c == OP_END) return NULL;    if (c == OP_END) return NULL;
   
Line 2062  for (;;) Line 2098  for (;;)
   else if (c == OP_CBRA || c == OP_SCBRA ||    else if (c == OP_CBRA || c == OP_SCBRA ||
            c == OP_CBRAPOS || c == OP_SCBRAPOS)             c == OP_CBRAPOS || c == OP_SCBRAPOS)
     {      {
    int n = GET2(code, 1+LINK_SIZE);    int n = (int)GET2(code, 1+LINK_SIZE);
     if (n == number) return (pcre_uchar *)code;      if (n == number) return (pcre_uchar *)code;
     code += PRIV(OP_lengths)[c];      code += PRIV(OP_lengths)[c];
     }      }
Line 2092  for (;;) Line 2128  for (;;)
       case OP_TYPEMINUPTO:        case OP_TYPEMINUPTO:
       case OP_TYPEEXACT:        case OP_TYPEEXACT:
       case OP_TYPEPOSUPTO:        case OP_TYPEPOSUPTO:
      if (code[1 + IMM2_SIZE] == OP_PROP      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
        || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2;        code += 2;
       break;        break;
   
       case OP_MARK:        case OP_MARK:
       case OP_PRUNE_ARG:        case OP_PRUNE_ARG:
       case OP_SKIP_ARG:        case OP_SKIP_ARG:
       code += code[1];  
       break;  
   
       case OP_THEN_ARG:        case OP_THEN_ARG:
       code += code[1];        code += code[1];
       break;        break;
Line 2115  for (;;) Line 2148  for (;;)
   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_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     if (utf) switch(c)      if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
Line 2167  instance of OP_RECURSE. Line 2200  instance of OP_RECURSE.
   
 Arguments:  Arguments:
   code        points to start of expression    code        points to start of expression
  utf         TRUE in UTF-8 / UTF-16 mode  utf         TRUE in UTF-8 / UTF-16 / UTF-32 mode
   
 Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found  Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
 */  */
Line 2177  find_recurse(const pcre_uchar *code, BOOL utf) Line 2210  find_recurse(const pcre_uchar *code, BOOL utf)
 {  {
 for (;;)  for (;;)
   {    {
  register int c = *code;  register pcre_uchar c = *code;
   if (c == OP_END) return NULL;    if (c == OP_END) return NULL;
   if (c == OP_RECURSE) return code;    if (c == OP_RECURSE) return code;
   
Line 2212  for (;;) Line 2245  for (;;)
       case OP_TYPEUPTO:        case OP_TYPEUPTO:
       case OP_TYPEMINUPTO:        case OP_TYPEMINUPTO:
       case OP_TYPEEXACT:        case OP_TYPEEXACT:
      if (code[1 + IMM2_SIZE] == OP_PROP      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
        || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2;        code += 2;
       break;        break;
   
       case OP_MARK:        case OP_MARK:
       case OP_PRUNE_ARG:        case OP_PRUNE_ARG:
       case OP_SKIP_ARG:        case OP_SKIP_ARG:
       code += code[1];  
       break;  
   
       case OP_THEN_ARG:        case OP_THEN_ARG:
       code += code[1];        code += code[1];
       break;        break;
Line 2235  for (;;) Line 2265  for (;;)
     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_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     if (utf) switch(c)      if (utf) switch(c)
       {        {
       case OP_CHAR:        case OP_CHAR:
Line 2321  bracket whose current branch will already have been sc Line 2351  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
  utf         TRUE if in UTF-8 / UTF-16 mode  utf         TRUE if in UTF-8 / UTF-16 / UTF-32 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
Line 2331  static BOOL Line 2361  static BOOL
 could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,  could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,
   BOOL utf, compile_data *cd)    BOOL utf, compile_data *cd)
 {  {
register int c;register pcre_uchar c;
 for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);  for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
      code < endcode;       code < endcode;
      code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))       code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))
Line 2365  for (code = first_significant_code(code + PRIV(OP_leng Line 2395  for (code = first_significant_code(code + PRIV(OP_leng
     /* Test for forward reference */      /* Test for forward reference */
   
     for (scode = cd->start_workspace; scode < cd->hwm; scode += LINK_SIZE)      for (scode = cd->start_workspace; scode < cd->hwm; scode += LINK_SIZE)
      if (GET(scode, 0) == code + 1 - cd->start_code) return TRUE;      if ((int)GET(scode, 0) == (int)(code + 1 - cd->start_code)) return TRUE;
   
     /* Not a forward reference, test for completed backward reference */      /* Not a forward reference, test for completed backward reference */
   
Line 2538  for (code = first_significant_code(code + PRIV(OP_leng Line 2568  for (code = first_significant_code(code + PRIV(OP_leng
     case OP_TYPEUPTO:      case OP_TYPEUPTO:
     case OP_TYPEMINUPTO:      case OP_TYPEMINUPTO:
     case OP_TYPEPOSUPTO:      case OP_TYPEPOSUPTO:
    if (code[1 + IMM2_SIZE] == OP_PROP    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
      || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2;      code += 2;
     break;      break;
   
     /* End of branch */      /* End of branch */
Line 2554  for (code = first_significant_code(code + PRIV(OP_leng Line 2584  for (code = first_significant_code(code + PRIV(OP_leng
     /* 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_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     case OP_STAR:      case OP_STAR:
     case OP_STARI:      case OP_STARI:
     case OP_MINSTAR:      case OP_MINSTAR:
Line 2586  for (code = first_significant_code(code + PRIV(OP_leng Line 2616  for (code = first_significant_code(code + PRIV(OP_leng
     case OP_MARK:      case OP_MARK:
     case OP_PRUNE_ARG:      case OP_PRUNE_ARG:
     case OP_SKIP_ARG:      case OP_SKIP_ARG:
     code += code[1];  
     break;  
   
     case OP_THEN_ARG:      case OP_THEN_ARG:
     code += code[1];      code += code[1];
     break;      break;
Line 2620  Arguments: Line 2647  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
  utf         TRUE if in UTF-8 / UTF-16 mode  utf         TRUE if in UTF-8 / UTF-16 / UTF-32 mode
   cd          pointers to tables etc    cd          pointers to tables etc
   
 Returns:      TRUE if what is matched could be empty  Returns:      TRUE if what is matched could be empty
Line 2686  Returns:   TRUE or FALSE Line 2713  Returns:   TRUE or FALSE
 static BOOL  static BOOL
 check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr)  check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr)
 {  {
int terminator;          /* Don't combine these lines; the Solaris cc */pcre_uchar terminator;          /* Don't combine these lines; the Solaris cc */
 terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */  terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
for (++ptr; *ptr != 0; ptr++)for (++ptr; *ptr != CHAR_NULL; ptr++)
   {    {
   if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)    if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
     ptr++;      ptr++;
Line 2735  register int yield = 0; Line 2762  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_UC_C8(ptr, pn, len) == 0) return yield;    STRNCMP_UC_C8(ptr, pn, (unsigned int)len) == 0) return yield;
   pn += posix_name_lengths[yield] + 1;    pn += posix_name_lengths[yield] + 1;
   yield++;    yield++;
   }    }
Line 2767  value in the reference (which is a group number). Line 2794  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
  utf        TRUE in UTF-8 / UTF-16 mode  utf        TRUE in UTF-8 / UTF-16 / UTF-32 mode
   cd         contains pointers to tables etc.    cd         contains pointers to tables etc.
   save_hwm   the hwm forward reference pointer at the start of the group    save_hwm   the hwm forward reference pointer at the start of the group
   
Line 2790  while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != Line 2817  while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) !=
   
   for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)    for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
     {      {
    offset = GET(hc, 0);    offset = (int)GET(hc, 0);
     if (cd->start_code + offset == ptr + 1)      if (cd->start_code + offset == ptr + 1)
       {        {
       PUT(hc, 0, offset + adjust);        PUT(hc, 0, offset + adjust);
Line 2803  while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != Line 2830  while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) !=
   
   if (hc >= cd->hwm)    if (hc >= cd->hwm)
     {      {
    offset = GET(ptr, 1);    offset = (int)GET(ptr, 1);
     if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);      if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);
     }      }
   
Line 2871  PUT(previous_callout, 2 + LINK_SIZE, length); Line 2898  PUT(previous_callout, 2 + LINK_SIZE, length);
 *************************************************/  *************************************************/
   
 /* This function is passed the start and end of a class range, in UTF-8 mode  /* This function is passed the start and end of a class range, in UTF-8 mode
with UCP support. It searches up the characters, looking for internal ranges ofwith UCP support. It searches up the characters, looking for ranges of
 characters in the "other" case. Each call returns the next one, updating the  characters in the "other" case. Each call returns the next one, updating the
start address.start address. A character with multiple other cases is returned on its own
 with a special return value.
   
 Arguments:  Arguments:
   cptr        points to starting character value; updated    cptr        points to starting character value; updated
Line 2881  Arguments: Line 2909  Arguments:
   ocptr       where to put start of othercase range    ocptr       where to put start of othercase range
   odptr       where to put end of othercase range    odptr       where to put end of othercase range
   
Yield:        TRUE when range returned; FALSE when no moreYield:        -1 when no more
                0 when a range is returned
               >0 the CASESET offset for char with multiple other cases
                 in this case, ocptr contains the original
 */  */
   
static BOOLstatic int
get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr,get_othercase_range(pcre_uint32 *cptr, pcre_uint32 d, pcre_uint32 *ocptr,
  unsigned int *odptr)  pcre_uint32 *odptr)
 {  {
unsigned int c, othercase, next;pcre_uint32 c, othercase, next;
 unsigned int co;
   
   /* Find the first character that has an other case. If it has multiple other
   cases, return its case offset value. */
   
 for (c = *cptr; c <= d; c++)  for (c = *cptr; c <= d; c++)
  { if ((othercase = UCD_OTHERCASE(c)) != c) break; }  {
   if ((co = UCD_CASESET(c)) != 0)
     {
     *ocptr = c++;   /* Character that has the set */
     *cptr = c;      /* Rest of input range */
     return (int)co;
     }
   if ((othercase = UCD_OTHERCASE(c)) != c) break;
   }
   
if (c > d) return FALSE;if (c > d) return -1;  /* Reached end of range */
   
 *ocptr = othercase;  *ocptr = othercase;
 next = othercase + 1;  next = othercase + 1;
Line 2904  for (++c; c <= d; c++) Line 2947  for (++c; c <= d; c++)
   next++;    next++;
   }    }
   
*odptr = next - 1;*odptr = next - 1;     /* End of othercase range */
*cptr = c;*cptr = c;             /* Rest of input range */
return 0;
return TRUE; 
 }  }
   
   
Line 2929  Returns:       TRUE if auto-possessifying is OK Line 2971  Returns:       TRUE if auto-possessifying is OK
 */  */
   
 static BOOL  static BOOL
check_char_prop(int c, int ptype, int pdata, BOOL negated)check_char_prop(pcre_uint32 c, unsigned int ptype, unsigned int pdata, BOOL negated)
 {  {
   #ifdef SUPPORT_UCP
   const pcre_uint32 *p;
   #endif
   
 const ucd_record *prop = GET_UCD(c);  const ucd_record *prop = GET_UCD(c);
   
 switch(ptype)  switch(ptype)
   {    {
   case PT_LAMP:    case PT_LAMP:
Line 2969  switch(ptype) Line 3016  switch(ptype)
   return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||    return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
           PRIV(ucp_gentype)[prop->chartype] == ucp_N ||            PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
           c == CHAR_UNDERSCORE) == negated;            c == CHAR_UNDERSCORE) == negated;
   
   #ifdef SUPPORT_UCP
     case PT_CLIST:
     p = PRIV(ucd_caseless_sets) + prop->caseset;
     for (;;)
       {
       if (c < *p) return !negated;
       if (c == *p++) return negated;
       }
     break;  /* Control never reaches here */
   #endif
   }    }
   
 return FALSE;  return FALSE;
 }  }
 #endif  /* SUPPORT_UCP */  #endif  /* SUPPORT_UCP */
Line 2986  sense to automatically possessify the repeated item. Line 3045  sense to automatically possessify the repeated item.
   
 Arguments:  Arguments:
   previous      pointer to the repeated opcode    previous      pointer to the repeated opcode
  utf           TRUE in UTF-8 / UTF-16 mode  utf           TRUE in UTF-8 / UTF-16 / UTF-32 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 2998  static BOOL Line 3057  static BOOL
 check_auto_possessive(const pcre_uchar *previous, BOOL utf,  check_auto_possessive(const pcre_uchar *previous, BOOL utf,
   const pcre_uchar *ptr, int options, compile_data *cd)    const pcre_uchar *ptr, int options, compile_data *cd)
 {  {
pcre_int32 c, next;pcre_uint32 c = NOTACHAR;
int op_code = *previous++;pcre_uint32 next;
 int escape;
 pcre_uchar op_code = *previous++;
   
 /* Skip whitespace and comments in extended mode */  /* Skip whitespace and comments in extended mode */
   
Line 3011  if ((options & PCRE_EXTENDED) != 0) Line 3072  if ((options & PCRE_EXTENDED) != 0)
     if (*ptr == CHAR_NUMBER_SIGN)      if (*ptr == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
      while (*ptr != 0)      while (*ptr != CHAR_NULL)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }          if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }
         ptr++;          ptr++;
Line 3030  value is a character, a negative value is an escape va Line 3091  value is a character, a negative value is an escape va
 if (*ptr == CHAR_BACKSLASH)  if (*ptr == CHAR_BACKSLASH)
   {    {
   int temperrorcode = 0;    int temperrorcode = 0;
  next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE);  escape = check_escape(&ptr, &next, &temperrorcode, cd->bracount, options,
     FALSE);
   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 (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_meta) == 0)
   {    {
     escape = 0;
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
   if (utf) { GETCHARINC(next, ptr); } else    if (utf) { GETCHARINC(next, ptr); } else
 #endif  #endif
Line 3053  if ((options & PCRE_EXTENDED) != 0) Line 3116  if ((options & PCRE_EXTENDED) != 0)
     if (*ptr == CHAR_NUMBER_SIGN)      if (*ptr == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
      while (*ptr != 0)      while (*ptr != CHAR_NULL)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }          if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; }
         ptr++;          ptr++;
Line 3072  if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MAR Line 3135  if (*ptr == CHAR_ASTERISK || *ptr == CHAR_QUESTION_MAR
   STRNCMP_UC_C8(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/* If the previous item is a character, get its value. */
the next item is a character. */ 
   
if (next >= 0) switch(op_code)if (op_code == OP_CHAR || op_code == OP_CHARI ||
     op_code == OP_NOT || op_code == OP_NOTI)
   {    {
   case OP_CHAR:  
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
   GETCHARTEST(c, previous);    GETCHARTEST(c, previous);
 #else  #else
   c = *previous;    c = *previous;
 #endif  #endif
  return c != next;  }
   
  /* For CHARI (caseless character) we must check the other case. If we have/* Now compare the next item with the previous opcode. First, handle cases when
  Unicode property support, we can use it to test the other case ofthe next item is a character. */
  high-valued characters. */ 
   
  case OP_CHARI:if (escape == 0)
#ifdef SUPPORT_UTF  {
  GETCHARTEST(c, previous);  /* For a caseless UTF match, the next character may have more than one other
#else  case, which maps to the special PT_CLIST property. Check this first. */
  c = *previous;
 #ifdef SUPPORT_UCP
   if (utf && c != NOTACHAR && (options & PCRE_CASELESS) != 0)
     {
     unsigned int ocs = UCD_CASESET(next);
     if (ocs > 0) return check_char_prop(c, PT_CLIST, ocs, op_code >= OP_NOT);
     }
 #endif  #endif
  if (c == next) return FALSE;
#ifdef SUPPORT_UTF  switch(op_code)
  if (utf) 
     {      {
    unsigned int othercase;    case OP_CHAR:
    if (next < 128) othercase = cd->fcc[next]; else    return c != next;
 
     /* For CHARI (caseless character) we must check the other case. If we have
     Unicode property support, we can use it to test the other case of
     high-valued characters. We know that next can have only one other case,
     because multi-other-case characters are dealt with above. */
 
     case OP_CHARI:
     if (c == next) return FALSE;
 #ifdef SUPPORT_UTF
     if (utf)
       {
       pcre_uint32 othercase;
       if (next < 128) othercase = cd->fcc[next]; else
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
    othercase = UCD_OTHERCASE((unsigned int)next);      othercase = UCD_OTHERCASE(next);
 #else  #else
    othercase = NOTACHAR;      othercase = NOTACHAR;
 #endif  #endif
    return (unsigned int)c != othercase;      return c != othercase;
    }      }
  else    else
 #endif  /* SUPPORT_UTF */  #endif  /* SUPPORT_UTF */
  return (c != TABLE_GET((unsigned int)next, cd->fcc, next));  /* Non-UTF-8 mode */    return (c != TABLE_GET(next, cd->fcc, next));  /* Not UTF */
   
  case OP_NOT:    case OP_NOT:
#ifdef SUPPORT_UTF    return c == next;
  GETCHARTEST(c, previous); 
#else 
  c = *previous; 
#endif 
  return c == next; 
   
  case OP_NOTI:    case OP_NOTI:
     if (c == next) return TRUE;
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
  GETCHARTEST(c, previous);    if (utf)
#else      {
  c = *previous;      pcre_uint32 othercase;
#endif      if (next < 128) othercase = cd->fcc[next]; else
  if (c == next) return TRUE; 
#ifdef SUPPORT_UTF 
  if (utf) 
    { 
    unsigned int othercase; 
    if (next < 128) othercase = cd->fcc[next]; else 
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
    othercase = UCD_OTHERCASE((unsigned int)next);      othercase = UCD_OTHERCASE(next);
 #else  #else
    othercase = NOTACHAR;      othercase = NOTACHAR;
 #endif  #endif
    return (unsigned int)c == othercase;      return c == othercase;
    }      }
  else    else
 #endif  /* SUPPORT_UTF */  #endif  /* SUPPORT_UTF */
  return (c == TABLE_GET((unsigned int)next, cd->fcc, next));  /* Non-UTF-8 mode */    return (c == TABLE_GET(next, cd->fcc, next));  /* Not UTF */
   
  /* 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. */
   
  case OP_DIGIT:    case OP_DIGIT:
  return next > 255 || (cd->ctypes[next] & ctype_digit) == 0;    return next > 255 || (cd->ctypes[next] & ctype_digit) == 0;
   
  case OP_NOT_DIGIT:    case OP_NOT_DIGIT:
  return next <= 255 && (cd->ctypes[next] & ctype_digit) != 0;    return next <= 255 && (cd->ctypes[next] & ctype_digit) != 0;
   
  case OP_WHITESPACE:    case OP_WHITESPACE:
  return next > 255 || (cd->ctypes[next] & ctype_space) == 0;    return next > 255 || (cd->ctypes[next] & ctype_space) == 0;
   
  case OP_NOT_WHITESPACE:    case OP_NOT_WHITESPACE:
  return next <= 255 && (cd->ctypes[next] & ctype_space) != 0;    return next <= 255 && (cd->ctypes[next] & ctype_space) != 0;
   
  case OP_WORDCHAR:    case OP_WORDCHAR:
  return next > 255 || (cd->ctypes[next] & ctype_word) == 0;    return next > 255 || (cd->ctypes[next] & ctype_word) == 0;
   
  case OP_NOT_WORDCHAR:    case OP_NOT_WORDCHAR:
  return next <= 255 && (cd->ctypes[next] & ctype_word) != 0;    return next <= 255 && (cd->ctypes[next] & ctype_word) != 0;
   
  case OP_HSPACE:    case OP_HSPACE:
  case OP_NOT_HSPACE:    case OP_NOT_HSPACE:
  switch(next)    switch(next)
    {      {
    case 0x09:      HSPACE_CASES:
    case 0x20:      return op_code == OP_NOT_HSPACE;
    case 0xa0: 
    case 0x1680: 
    case 0x180e: 
    case 0x2000: 
    case 0x2001: 
    case 0x2002: 
    case 0x2003: 
    case 0x2004: 
    case 0x2005: 
    case 0x2006: 
    case 0x2007: 
    case 0x2008: 
    case 0x2009: 
    case 0x200A: 
    case 0x202f: 
    case 0x205f: 
    case 0x3000: 
    return op_code == OP_NOT_HSPACE; 
    default: 
    return op_code != OP_NOT_HSPACE; 
    } 
   
  case OP_ANYNL:      default:
  case OP_VSPACE:      return op_code != OP_NOT_HSPACE;
  case OP_NOT_VSPACE:      }
  switch(next) 
    { 
    case 0x0a: 
    case 0x0b: 
    case 0x0c: 
    case 0x0d: 
    case 0x85: 
    case 0x2028: 
    case 0x2029: 
    return op_code == OP_NOT_VSPACE; 
    default: 
    return op_code != OP_NOT_VSPACE; 
    } 
   
       case OP_ANYNL:
       case OP_VSPACE:
       case OP_NOT_VSPACE:
       switch(next)
         {
         VSPACE_CASES:
         return op_code == OP_NOT_VSPACE;
   
         default:
         return op_code != OP_NOT_VSPACE;
         }
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
  case OP_PROP:    case OP_PROP:
  return check_char_prop(next, previous[0], previous[1], FALSE);    return check_char_prop(next, previous[0], previous[1], FALSE);
   
  case OP_NOTPROP:    case OP_NOTPROP:
  return check_char_prop(next, previous[0], previous[1], TRUE);    return check_char_prop(next, previous[0], previous[1], TRUE);
 #endif  #endif
   
  default:    default:
  return FALSE;    return FALSE;
     }
   }    }
   
   
 /* Handle the case when the next item is \d, \s, etc. Note that when PCRE_UCP  /* Handle the case when the next item is \d, \s, etc. Note that when PCRE_UCP
 is set, \d turns into ESC_du rather than ESC_d, etc., so ESC_d etc. are  is set, \d turns into ESC_du rather than ESC_d, etc., so ESC_d etc. are
 generated only when PCRE_UCP is *not* set, that is, when only ASCII  generated only when PCRE_UCP is *not* set, that is, when only ASCII
Line 3232  switch(op_code) Line 3279  switch(op_code)
   {    {
   case OP_CHAR:    case OP_CHAR:
   case OP_CHARI:    case OP_CHARI:
#ifdef SUPPORT_UTF  switch(escape)
  GETCHARTEST(c, previous); 
#else 
  c = *previous; 
#endif 
  switch(-next) 
     {      {
     case ESC_d:      case ESC_d:
     return c > 255 || (cd->ctypes[c] & ctype_digit) == 0;      return c > 255 || (cd->ctypes[c] & ctype_digit) == 0;
Line 3261  switch(op_code) Line 3303  switch(op_code)
     case ESC_H:      case ESC_H:
     switch(c)      switch(c)
       {        {
      case 0x09:      HSPACE_CASES:
      case 0x20:      return escape != ESC_h;
      case 0xa0:
      case 0x1680: 
      case 0x180e: 
      case 0x2000: 
      case 0x2001: 
      case 0x2002: 
      case 0x2003: 
      case 0x2004: 
      case 0x2005: 
      case 0x2006: 
      case 0x2007: 
      case 0x2008: 
      case 0x2009: 
      case 0x200A: 
      case 0x202f: 
      case 0x205f: 
      case 0x3000: 
      return -next != ESC_h; 
       default:        default:
      return -next == ESC_h;      return escape == ESC_h;
       }        }
   
     case ESC_v:      case ESC_v:
     case ESC_V:      case ESC_V:
     switch(c)      switch(c)
       {        {
      case 0x0a:      VSPACE_CASES:
      case 0x0b:      return escape != ESC_v;
      case 0x0c:
      case 0x0d: 
      case 0x85: 
      case 0x2028: 
      case 0x2029: 
      return -next != ESC_v; 
       default:        default:
      return -next == ESC_v;      return escape == ESC_v;
       }        }
   
     /* When PCRE_UCP is set, these values get generated for \d etc. Find      /* When PCRE_UCP is set, these values get generated for \d etc. Find
     their substitutions and process them. The result will always be either      their substitutions and process them. The result will always be either
    -ESC_p or -ESC_P. Then fall through to process those values. */    ESC_p or ESC_P. Then fall through to process those values. */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
     case ESC_du:      case ESC_du:
Line 3314  switch(op_code) Line 3334  switch(op_code)
     case ESC_SU:      case ESC_SU:
       {        {
       int temperrorcode = 0;        int temperrorcode = 0;
      ptr = substitutes[-next - ESC_DU];      ptr = substitutes[escape - ESC_DU];
      next = check_escape(&ptr, &temperrorcode, 0, options, FALSE);      escape = check_escape(&ptr, &next, &temperrorcode, 0, options, FALSE);
       if (temperrorcode != 0) return FALSE;        if (temperrorcode != 0) return FALSE;
       ptr++;    /* For compatibility */        ptr++;    /* For compatibility */
       }        }
Line 3324  switch(op_code) Line 3344  switch(op_code)
     case ESC_p:      case ESC_p:
     case ESC_P:      case ESC_P:
       {        {
      int ptype, pdata, errorcodeptr;      unsigned int ptype = 0, pdata = 0;
       int errorcodeptr;
       BOOL negated;        BOOL negated;
   
       ptr--;      /* Make ptr point at the p or P */        ptr--;      /* Make ptr point at the p or P */
      ptype = get_ucp(&ptr, &negated, &pdata, &errorcodeptr);      if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcodeptr))
      if (ptype < 0) return FALSE;        return FALSE;
       ptr++;      /* Point past the final curly ket */        ptr++;      /* Point past the final curly ket */
   
       /* If the property item is optional, we have to give up. (When generated        /* If the property item is optional, we have to give up. (When generated
Line 3342  switch(op_code) Line 3363  switch(op_code)
   
       /* Do the property check. */        /* Do the property check. */
   
      return check_char_prop(c, ptype, pdata, (next == -ESC_P) != negated);      return check_char_prop(c, ptype, pdata, (escape == ESC_P) != negated);
       }        }
 #endif  #endif
   
Line 3357  switch(op_code) Line 3378  switch(op_code)
   these op-codes are never generated.) */    these op-codes are never generated.) */
   
   case OP_DIGIT:    case OP_DIGIT:
  return next == -ESC_D || next == -ESC_s || next == -ESC_W ||  return escape == ESC_D || escape == ESC_s || escape == ESC_W ||
         next == -ESC_h || next == -ESC_v || next == -ESC_R;         escape == ESC_h || escape == ESC_v || escape == ESC_R;
   
   case OP_NOT_DIGIT:    case OP_NOT_DIGIT:
  return next == -ESC_d;  return escape == ESC_d;
   
   case OP_WHITESPACE:    case OP_WHITESPACE:
  return next == -ESC_S || next == -ESC_d || next == -ESC_w;  return escape == ESC_S || escape == ESC_d || escape == ESC_w;
   
   case OP_NOT_WHITESPACE:    case OP_NOT_WHITESPACE:
  return next == -ESC_s || next == -ESC_h || next == -ESC_v || next == -ESC_R;  return escape == ESC_s || escape == ESC_h || escape == ESC_v || escape == ESC_R;
   
   case OP_HSPACE:    case OP_HSPACE:
  return next == -ESC_S || next == -ESC_H || next == -ESC_d ||  return escape == ESC_S || escape == ESC_H || escape == ESC_d ||
         next == -ESC_w || next == -ESC_v || next == -ESC_R;         escape == ESC_w || escape == ESC_v || escape == ESC_R;
   
   case OP_NOT_HSPACE:    case OP_NOT_HSPACE:
  return next == -ESC_h;  return escape == ESC_h;
   
   /* Can't have \S in here because VT matches \S (Perl anomaly) */    /* Can't have \S in here because VT matches \S (Perl anomaly) */
   case OP_ANYNL:    case OP_ANYNL:
   case OP_VSPACE:    case OP_VSPACE:
  return next == -ESC_V || next == -ESC_d || next == -ESC_w;  return escape == ESC_V || escape == ESC_d || escape == ESC_w;
   
   case OP_NOT_VSPACE:    case OP_NOT_VSPACE:
  return next == -ESC_v || next == -ESC_R;  return escape == ESC_v || escape == ESC_R;
   
   case OP_WORDCHAR:    case OP_WORDCHAR:
  return next == -ESC_W || next == -ESC_s || next == -ESC_h ||  return escape == ESC_W || escape == ESC_s || escape == ESC_h ||
         next == -ESC_v || next == -ESC_R;         escape == ESC_v || escape == ESC_R;
   
   case OP_NOT_WORDCHAR:    case OP_NOT_WORDCHAR:
  return next == -ESC_w || next == -ESC_d;  return escape == ESC_w || escape == ESC_d;
   
   default:    default:
   return FALSE;    return FALSE;
Line 3401  switch(op_code) Line 3422  switch(op_code)
   
   
 /*************************************************  /*************************************************
   *        Add a character or range to a class     *
   *************************************************/
   
   /* This function packages up the logic of adding a character or range of
   characters to a class. The character values in the arguments will be within the
   valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
   mutually recursive with the function immediately below.
   
   Arguments:
     classbits     the bit map for characters < 256
     uchardptr     points to the pointer for extra data
     options       the options word
     cd            contains pointers to tables etc.
     start         start of range character
     end           end of range character
   
   Returns:        the number of < 256 characters added
                   the pointer to extra data is updated
   */
   
   static int
   add_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
     compile_data *cd, pcre_uint32 start, pcre_uint32 end)
   {
   pcre_uint32 c;
   int n8 = 0;
   
   /* If caseless matching is required, scan the range and process alternate
   cases. In Unicode, there are 8-bit characters that have alternate cases that
   are greater than 255 and vice-versa. Sometimes we can just extend the original
   range. */
   
   if ((options & PCRE_CASELESS) != 0)
     {
   #ifdef SUPPORT_UCP
     if ((options & PCRE_UTF8) != 0)
       {
       int rc;
       pcre_uint32 oc, od;
   
       options &= ~PCRE_CASELESS;   /* Remove for recursive calls */
       c = start;
   
       while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
         {
         /* Handle a single character that has more than one other case. */
   
         if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cd,
           PRIV(ucd_caseless_sets) + rc, oc);
   
         /* Do nothing if the other case range is within the original range. */
   
         else if (oc >= start && od <= end) continue;
   
         /* Extend the original range if there is overlap, noting that if oc < c, we
         can't have od > end because a subrange is always shorter than the basic
         range. Otherwise, use a recursive call to add the additional range. */
   
         else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
         else if (od > end && oc <= end + 1) end = od;       /* Extend upwards */
         else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od);
         }
       }
     else
   #endif  /* SUPPORT_UCP */
   
     /* Not UTF-mode, or no UCP */
   
     for (c = start; c <= end && c < 256; c++)
       {
       SETBIT(classbits, cd->fcc[c]);
       n8++;
       }
     }
   
   /* Now handle the original range. Adjust the final value according to the bit
   length - this means that the same lists of (e.g.) horizontal spaces can be used
   in all cases. */
   
   #if defined COMPILE_PCRE8
   #ifdef SUPPORT_UTF
     if ((options & PCRE_UTF8) == 0)
   #endif
     if (end > 0xff) end = 0xff;
   
   #elif defined COMPILE_PCRE16
   #ifdef SUPPORT_UTF
     if ((options & PCRE_UTF16) == 0)
   #endif
     if (end > 0xffff) end = 0xffff;
   
   #endif /* COMPILE_PCRE[8|16] */
   
   /* If all characters are less than 256, use the bit map. Otherwise use extra
   data. */
   
   if (end < 0x100)
     {
     for (c = start; c <= end; c++)
       {
       n8++;
       SETBIT(classbits, c);
       }
     }
   
   else
     {
     pcre_uchar *uchardata = *uchardptr;
   
   #ifdef SUPPORT_UTF
     if ((options & PCRE_UTF8) != 0)  /* All UTFs use the same flag bit */
       {
       if (start < end)
         {
         *uchardata++ = XCL_RANGE;
         uchardata += PRIV(ord2utf)(start, uchardata);
         uchardata += PRIV(ord2utf)(end, uchardata);
         }
       else if (start == end)
         {
         *uchardata++ = XCL_SINGLE;
         uchardata += PRIV(ord2utf)(start, uchardata);
         }
       }
     else
   #endif  /* SUPPORT_UTF */
   
     /* Without UTF support, character values are constrained by the bit length,
     and can only be > 256 for 16-bit and 32-bit libraries. */
   
   #ifdef COMPILE_PCRE8
       {}
   #else
     if (start < end)
       {
       *uchardata++ = XCL_RANGE;
       *uchardata++ = start;
       *uchardata++ = end;
       }
     else if (start == end)
       {
       *uchardata++ = XCL_SINGLE;
       *uchardata++ = start;
       }
   #endif
   
     *uchardptr = uchardata;   /* Updata extra data pointer */
     }
   
   return n8;    /* Number of 8-bit characters */
   }
   
   
   
   
   /*************************************************
   *        Add a list of characters to a class     *
   *************************************************/
   
   /* This function is used for adding a list of case-equivalent characters to a
   class, and also for adding a list of horizontal or vertical whitespace. If the
   list is in order (which it should be), ranges of characters are detected and
   handled appropriately. This function is mutually recursive with the function
   above.
   
   Arguments:
     classbits     the bit map for characters < 256
     uchardptr     points to the pointer for extra data
     options       the options word
     cd            contains pointers to tables etc.
     p             points to row of 32-bit values, terminated by NOTACHAR
     except        character to omit; this is used when adding lists of
                     case-equivalent characters to avoid including the one we
                     already know about
   
   Returns:        the number of < 256 characters added
                   the pointer to extra data is updated
   */
   
   static int
   add_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
     compile_data *cd, const pcre_uint32 *p, unsigned int except)
   {
   int n8 = 0;
   while (p[0] < NOTACHAR)
     {
     int n = 0;
     if (p[0] != except)
       {
       while(p[n+1] == p[0] + n + 1) n++;
       n8 += add_to_class(classbits, uchardptr, options, cd, p[0], p[n]);
       }
     p += n + 1;
     }
   return n8;
   }
   
   
   
   /*************************************************
   *    Add characters not in a list to a class     *
   *************************************************/
   
   /* This function is used for adding the complement of a list of horizontal or
   vertical whitespace to a class. The list must be in order.
   
   Arguments:
     classbits     the bit map for characters < 256
     uchardptr     points to the pointer for extra data
     options       the options word
     cd            contains pointers to tables etc.
     p             points to row of 32-bit values, terminated by NOTACHAR
   
   Returns:        the number of < 256 characters added
                   the pointer to extra data is updated
   */
   
   static int
   add_not_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr,
     int options, compile_data *cd, const pcre_uint32 *p)
   {
   BOOL utf = (options & PCRE_UTF8) != 0;
   int n8 = 0;
   if (p[0] > 0)
     n8 += add_to_class(classbits, uchardptr, options, cd, 0, p[0] - 1);
   while (p[0] < NOTACHAR)
     {
     while (p[1] == p[0] + 1) p++;
     n8 += add_to_class(classbits, uchardptr, options, cd, p[0] + 1,
       (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
     p++;
     }
   return n8;
   }
   
   
   
   /*************************************************
 *           Compile one branch                   *  *           Compile one branch                   *
 *************************************************/  *************************************************/
   
Line 3415  Arguments: Line 3674  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
  firstcharptr   set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)  firstcharptr    place to put the first required character
  reqcharptr     set to the last literal character required, else < 0  firstcharflagsptr place to put the first character flags, or a negative number
   reqcharptr     place to put the last required character
   reqcharflagsptr place to put the last required character flags, or a negative number
   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 3429  Returns:         TRUE on success Line 3690  Returns:         TRUE on success
   
 static BOOL  static BOOL
 compile_branch(int *optionsptr, pcre_uchar **codeptr,  compile_branch(int *optionsptr, pcre_uchar **codeptr,
  const pcre_uchar **ptrptr, int *errorcodeptr, pcre_int32 *firstcharptr,  const pcre_uchar **ptrptr, int *errorcodeptr,
  pcre_int32 *reqcharptr, branch_chain *bcptr, int cond_depth,  pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
   pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
   branch_chain *bcptr, int cond_depth,
   compile_data *cd, int *lengthptr)    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;
pcre_int32 firstchar, reqchar;pcre_uint32 firstchar, reqchar;
pcre_int32 zeroreqchar, zerofirstchar;pcre_int32 firstcharflags, reqcharflags;
 pcre_uint32 zeroreqchar, zerofirstchar;
 pcre_int32 zeroreqcharflags, zerofirstcharflags;
 pcre_int32 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 pcre_uint32 c;
 int escape;
 register pcre_uchar *code = *codeptr;  register pcre_uchar *code = *codeptr;
 pcre_uchar *last_code = code;  pcre_uchar *last_code = code;
 pcre_uchar *orig_code = code;  pcre_uchar *orig_code = code;
Line 3463  must not do this for other options (e.g. PCRE_EXTENDED Line 3729  must not do this for other options (e.g. PCRE_EXTENDED
 dynamically as we process the pattern. */  dynamically as we process the pattern. */
   
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
/* PCRE_UTF16 has the same value as PCRE_UTF8. *//* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
 BOOL utf = (options & PCRE_UTF8) != 0;  BOOL utf = (options & PCRE_UTF8) != 0;
   #ifndef COMPILE_PCRE32
 pcre_uchar utf_chars[6];  pcre_uchar utf_chars[6];
   #endif
 #else  #else
 BOOL utf = FALSE;  BOOL utf = FALSE;
 #endif  #endif
   
/* Helper variables for OP_XCLASS opcode (for characters > 255). *//* Helper variables for OP_XCLASS opcode (for characters > 255). We define
 class_uchardata always so that it can be passed to add_to_class() always,
 though it will not be used in non-UTF 8-bit cases. This avoids having to supply
 alternative calls for the different cases. */
   
   pcre_uchar *class_uchardata;
 #if defined SUPPORT_UTF || !defined COMPILE_PCRE8  #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
 BOOL xclass;  BOOL xclass;
 pcre_uchar *class_uchardata;  
 pcre_uchar *class_uchardata_base;  pcre_uchar *class_uchardata_base;
 #endif  #endif
   
Line 3497  to take the zero repeat into account. This is implemen Line 3768  to take the zero repeat into account. This is implemen
 zerofirstbyte and zeroreqchar when such a repeat is encountered. The individual  zerofirstbyte 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. */
   
firstchar = reqchar = zerofirstchar = zeroreqchar = REQ_UNSET;firstchar = reqchar = zerofirstchar = zeroreqchar = 0;
 firstcharflags = reqcharflags = zerofirstcharflags = zeroreqcharflags = REQ_UNSET;
   
 /* The variable req_caseopt contains either the REQ_CASELESS value  /* The variable req_caseopt contains either the REQ_CASELESS value
 or zero, according to the current setting of the caseless flag. The  or zero, according to the current setting of the caseless flag. The
Line 3518  for (;; ptr++) Line 3790  for (;; ptr++)
   BOOL is_recurse;    BOOL is_recurse;
   BOOL reset_bracount;    BOOL reset_bracount;
   int class_has_8bitchar;    int class_has_8bitchar;
  int class_single_char;  int class_one_char;
   int newoptions;    int newoptions;
   int recno;    int recno;
   int refsign;    int refsign;
   int skipbytes;    int skipbytes;
  int subreqchar;  pcre_uint32 subreqchar, subfirstchar;
  int subfirstchar;  pcre_int32 subreqcharflags, subfirstcharflags;
   int terminator;    int terminator;
  int mclength;  unsigned int mclength;
  int tempbracount;  unsigned int tempbracount;
   pcre_uint32 ec;
   pcre_uchar mcbuffer[8];    pcre_uchar mcbuffer[8];
   
   /* Get next character in the pattern */    /* Get next character in the pattern */
Line 3537  for (;; ptr++) Line 3810  for (;; ptr++)
   /* If we are at the end of a nested substitution, revert to the outer level    /* If we are at the end of a nested substitution, revert to the outer level
   string. Nesting only happens one level deep. */    string. Nesting only happens one level deep. */
   
  if (c == 0 && nestptr != NULL)  if (c == CHAR_NULL && nestptr != NULL)
     {      {
     ptr = nestptr;      ptr = nestptr;
     nestptr = NULL;      nestptr = NULL;
Line 3612  for (;; ptr++) Line 3885  for (;; ptr++)
   
   /* If in \Q...\E, check for the end; if not, we have a literal */    /* If in \Q...\E, check for the end; if not, we have a literal */
   
  if (inescq && c != 0)  if (inescq && c != CHAR_NULL)
     {      {
     if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)      if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
       {        {
Line 3660  for (;; ptr++) Line 3933  for (;; ptr++)
     if (c == CHAR_NUMBER_SIGN)      if (c == CHAR_NUMBER_SIGN)
       {        {
       ptr++;        ptr++;
      while (*ptr != 0)      while (*ptr != CHAR_NULL)
         {          {
         if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }          if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; }
         ptr++;          ptr++;
Line 3668  for (;; ptr++) Line 3941  for (;; ptr++)
         if (utf) FORWARDCHAR(ptr);          if (utf) FORWARDCHAR(ptr);
 #endif  #endif
         }          }
      if (*ptr != 0) continue;      if (*ptr != CHAR_NULL) continue;
   
       /* Else fall through to handle end of string */        /* Else fall through to handle end of string */
       c = 0;        c = 0;
Line 3690  for (;; ptr++) Line 3963  for (;; ptr++)
     case CHAR_VERTICAL_LINE:       /* or | or ) */      case CHAR_VERTICAL_LINE:       /* or | or ) */
     case CHAR_RIGHT_PARENTHESIS:      case CHAR_RIGHT_PARENTHESIS:
     *firstcharptr = firstchar;      *firstcharptr = firstchar;
       *firstcharflagsptr = firstcharflags;
     *reqcharptr = reqchar;      *reqcharptr = reqchar;
       *reqcharflagsptr = reqcharflags;
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
     if (lengthptr != NULL)      if (lengthptr != NULL)
Line 3714  for (;; ptr++) Line 3989  for (;; ptr++)
     previous = NULL;      previous = NULL;
     if ((options & PCRE_MULTILINE) != 0)      if ((options & PCRE_MULTILINE) != 0)
       {        {
      if (firstchar == REQ_UNSET) firstchar = REQ_NONE;      if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
       *code++ = OP_CIRCM;        *code++ = OP_CIRCM;
       }        }
     else *code++ = OP_CIRC;      else *code++ = OP_CIRC;
Line 3729  for (;; ptr++) Line 4004  for (;; ptr++)
     repeats. The value of reqchar doesn't change either. */      repeats. The value of reqchar doesn't change either. */
   
     case CHAR_DOT:      case CHAR_DOT:
    if (firstchar == REQ_UNSET) firstchar = REQ_NONE;    if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
     zerofirstchar = firstchar;      zerofirstchar = firstchar;
       zerofirstcharflags = firstcharflags;
     zeroreqchar = reqchar;      zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
     previous = code;      previous = code;
     *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;      *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;
     break;      break;
Line 3805  for (;; ptr++) Line 4082  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 (firstchar == REQ_UNSET) firstchar = REQ_NONE;      if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
       zerofirstchar = firstchar;        zerofirstchar = firstchar;
         zerofirstcharflags = firstcharflags;
       break;        break;
       }        }
   
Line 3816  for (;; ptr++) Line 4094  for (;; ptr++)
   
     should_flip_negation = FALSE;      should_flip_negation = FALSE;
   
    /* For optimization purposes, we track some properties of the class.    /* For optimization purposes, we track some properties of the class:
    class_has_8bitchar will be non-zero, if the class contains at least one    class_has_8bitchar will be non-zero if the class contains at least one <
    < 256 character. class_single_char will be 1 if the class contains only    256 character; class_one_char will be 1 if the class contains just one
    a single character. */    character. */
   
     class_has_8bitchar = 0;      class_has_8bitchar = 0;
    class_single_char = 0;    class_one_char = 0;
   
     /* Initialize the 32-char bit map to all zeros. We build the map in a      /* Initialize the 32-char bit map to all zeros. We build the map in a
    temporary bit of memory, in case the class contains only 1 character (less    temporary bit of memory, in case the class contains fewer than two
    than 256), because in that case the compiled code doesn't use the bit map.    8-bit characters because in that case the compiled code doesn't use the bit
    */    map. */
   
     memset(classbits, 0, 32 * sizeof(pcre_uint8));      memset(classbits, 0, 32 * sizeof(pcre_uint8));
   
 #if defined SUPPORT_UTF || !defined COMPILE_PCRE8  #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
    xclass = FALSE;                           /* No chars >= 256 */    xclass = FALSE;
    class_uchardata = code + LINK_SIZE + 2;   /* For UTF-8 items */    class_uchardata = code + LINK_SIZE + 2;   /* For XCLASS items */
    class_uchardata_base = class_uchardata;   /* For resetting in pass 1 */    class_uchardata_base = class_uchardata;   /* Save the start */
 #endif  #endif
   
     /* Process characters until ] is reached. By writing this as a "do" it      /* Process characters until ] is reached. By writing this as a "do" it
     means that an initial ] is taken as a data character. At the start of the      means that an initial ] is taken as a data character. At the start of the
     loop, c contains the first byte of the character. */      loop, c contains the first byte of the character. */
   
    if (c != 0) do    if (c != CHAR_NULL) do
       {        {
       const pcre_uchar *oldptr;        const pcre_uchar *oldptr;
   
Line 3856  for (;; ptr++) Line 4134  for (;; ptr++)
       /* In the pre-compile phase, accumulate the length of any extra        /* 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 > 255 characters no longer overwrite the work space        contain a zillion > 255 characters no longer overwrite the work space
      (which is on the stack). */      (which is on the stack). We have to remember that there was XCLASS data,
       however. */
   
      if (lengthptr != NULL)      if (lengthptr != NULL && class_uchardata > class_uchardata_base)
         {          {
           xclass = TRUE;
         *lengthptr += class_uchardata - class_uchardata_base;          *lengthptr += class_uchardata - class_uchardata_base;
         class_uchardata = class_uchardata_base;          class_uchardata = class_uchardata_base;
         }          }
Line 3961  for (;; ptr++) Line 4241  for (;; ptr++)
             for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];              for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];
           }            }
   
        /* Not see if we need to remove any special characters. An option        /* Now see if we need to remove any special characters. An option
         value of 1 removes vertical space and 2 removes underscore. */          value of 1 removes vertical space and 2 removes underscore. */
   
         if (tabopt < 0) tabopt = -tabopt;          if (tabopt < 0) tabopt = -tabopt;
Line 3977  for (;; ptr++) Line 4257  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;
        /* Every class contains at least one < 256 characters. */        /* Every class contains at least one < 256 character. */
         class_has_8bitchar = 1;          class_has_8bitchar = 1;
         /* Every class contains at least two characters. */          /* Every class contains at least two characters. */
        class_single_char = 2;        class_one_char = 2;
         continue;    /* End of POSIX syntax handling */          continue;    /* End of POSIX syntax handling */
         }          }
   
Line 3988  for (;; ptr++) Line 4268  for (;; ptr++)
       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        assume that other escapes have more than one character in them, so
      speculatively set both class_has_8bitchar and class_single_char bigger      speculatively set both class_has_8bitchar and class_one_char bigger
       than one. Unrecognized escapes fall through and are either treated        than one. Unrecognized escapes fall through and are either treated
       as literal characters (by default), or are faulted if        as literal characters (by default), or are faulted if
       PCRE_EXTRA is set. */        PCRE_EXTRA is set. */
   
       if (c == CHAR_BACKSLASH)        if (c == CHAR_BACKSLASH)
         {          {
        c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE);        escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options,
           TRUE);
         if (*errorcodeptr != 0) goto FAILED;          if (*errorcodeptr != 0) goto FAILED;
        if (escape == 0) c = ec;
        if (-c == ESC_b) c = CHAR_BS;    /* \b is backspace in a class */        else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */
        else if (-c == ESC_N)            /* \N is not supported in a class */        else if (escape == ESC_N)          /* \N is not supported in a class */
           {            {
           *errorcodeptr = ERR71;            *errorcodeptr = ERR71;
           goto FAILED;            goto FAILED;
           }            }
        else if (-c == ESC_Q)            /* Handle start of quoted string */        else if (escape == ESC_Q)            /* Handle start of quoted string */
           {            {
           if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)            if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
             {              {
Line 4013  for (;; ptr++) Line 4294  for (;; ptr++)
           else inescq = TRUE;            else inescq = TRUE;
           continue;            continue;
           }            }
        else if (-c == ESC_E) continue;  /* Ignore orphan \E */        else if (escape == ESC_E) continue;  /* Ignore orphan \E */
   
        if (c < 0)        else
           {            {
           register const pcre_uint8 *cbits = cd->cbits;            register const pcre_uint8 *cbits = cd->cbits;
           /* Every class contains at least two < 256 characters. */            /* Every class contains at least two < 256 characters. */
           class_has_8bitchar++;            class_has_8bitchar++;
           /* Every class contains at least two characters. */            /* Every class contains at least two characters. */
          class_single_char += 2;          class_one_char += 2;
   
          switch (-c)          switch (escape)
             {              {
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
             case ESC_du:     /* These are the values given for \d etc */              case ESC_du:     /* These are the values given for \d etc */
Line 4033  for (;; ptr++) Line 4314  for (;; ptr++)
             case ESC_su:     /* of the default ASCII testing. */              case ESC_su:     /* of the default ASCII testing. */
             case ESC_SU:              case ESC_SU:
             nestptr = ptr;              nestptr = ptr;
            ptr = substitutes[-c - ESC_DU] - 1;  /* Just before substitute */            ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
             class_has_8bitchar--;                /* Undo! */              class_has_8bitchar--;                /* Undo! */
             continue;              continue;
 #endif  #endif
Line 4057  for (;; ptr++) Line 4338  for (;; ptr++)
   
             /* Perl 5.004 onwards omits VT from \s, but we must preserve it              /* Perl 5.004 onwards omits VT from \s, but we must preserve it
             if it was previously set by something earlier in the character              if it was previously set by something earlier in the character
            class. */            class. Luckily, the value of CHAR_VT is 0x0b in both ASCII and
             EBCDIC, so we lazily just adjust the appropriate bit. */
   
             case ESC_s:              case ESC_s:
             classbits[0] |= cbits[cbit_space];              classbits[0] |= cbits[cbit_space];
Line 4071  for (;; ptr++) Line 4353  for (;; ptr++)
             classbits[1] |= 0x08;    /* Perl 5.004 onwards omits VT from \s */              classbits[1] |= 0x08;    /* Perl 5.004 onwards omits VT from \s */
             continue;              continue;
   
               /* The rest apply in both UCP and non-UCP cases. */
   
             case ESC_h:              case ESC_h:
            SETBIT(classbits, 0x09); /* VT */            (void)add_list_to_class(classbits, &class_uchardata, options, cd,
            SETBIT(classbits, 0x20); /* SPACE */              PRIV(hspace_list), NOTACHAR);
            SETBIT(classbits, 0xa0); /* NSBP */ 
#ifndef COMPILE_PCRE8 
            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) 
              { 
              xclass = TRUE; 
              *class_uchardata++ = XCL_SINGLE; 
              class_uchardata += PRIV(ord2utf)(0x1680, class_uchardata); 
              *class_uchardata++ = XCL_SINGLE; 
              class_uchardata += PRIV(ord2utf)(0x180e, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x2000, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x200a, class_uchardata); 
              *class_uchardata++ = XCL_SINGLE; 
              class_uchardata += PRIV(ord2utf)(0x202f, class_uchardata); 
              *class_uchardata++ = XCL_SINGLE; 
              class_uchardata += PRIV(ord2utf)(0x205f, class_uchardata); 
              *class_uchardata++ = XCL_SINGLE; 
              class_uchardata += PRIV(ord2utf)(0x3000, class_uchardata); 
              } 
#endif 
             continue;              continue;
   
             case ESC_H:              case ESC_H:
            for (c = 0; c < 32; c++)            (void)add_not_list_to_class(classbits, &class_uchardata, options,
              {              cd, PRIV(hspace_list));
              int x = 0xff; 
              switch (c) 
                { 
                case 0x09/8: x ^= 1 << (0x09%8); break; 
                case 0x20/8: x ^= 1 << (0x20%8); break; 
                case 0xa0/8: x ^= 1 << (0xa0%8); break; 
                default: break; 
                } 
              classbits[c] |= x; 
              } 
#ifndef COMPILE_PCRE8 
            xclass = TRUE; 
            *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) 
              { 
              xclass = TRUE; 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x167f, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x1681, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x180d, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x180f, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x1fff, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x200b, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x202e, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x2030, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x205e, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x2060, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x2fff, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x3001, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); 
              } 
#endif 
             continue;              continue;
   
             case ESC_v:              case ESC_v:
            SETBIT(classbits, 0x0a); /* LF */            (void)add_list_to_class(classbits, &class_uchardata, options, cd,
            SETBIT(classbits, 0x0b); /* VT */              PRIV(vspace_list), NOTACHAR);
            SETBIT(classbits, 0x0c); /* FF */ 
            SETBIT(classbits, 0x0d); /* CR */ 
            SETBIT(classbits, 0x85); /* NEL */ 
#ifndef COMPILE_PCRE8 
            xclass = TRUE; 
            *class_uchardata++ = XCL_RANGE; 
            *class_uchardata++ = 0x2028; 
            *class_uchardata++ = 0x2029; 
#elif defined SUPPORT_UTF 
            if (utf) 
              { 
              xclass = TRUE; 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x2028, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x2029, class_uchardata); 
              } 
#endif 
             continue;              continue;
   
             case ESC_V:              case ESC_V:
            for (c = 0; c < 32; c++)            (void)add_not_list_to_class(classbits, &class_uchardata, options,
              {              cd, PRIV(vspace_list));
              int x = 0xff; 
              switch (c) 
                { 
                case 0x0a/8: x ^= 1 << (0x0a%8); 
                             x ^= 1 << (0x0b%8); 
                             x ^= 1 << (0x0c%8); 
                             x ^= 1 << (0x0d%8); 
                             break; 
                case 0x85/8: x ^= 1 << (0x85%8); break; 
                default: break; 
                } 
              classbits[c] |= x; 
              } 
 
#ifndef COMPILE_PCRE8 
            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) 
              { 
              xclass = TRUE; 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x0100, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x2027, class_uchardata); 
              *class_uchardata++ = XCL_RANGE; 
              class_uchardata += PRIV(ord2utf)(0x202a, class_uchardata); 
              class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); 
              } 
#endif 
             continue;              continue;
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
Line 4252  for (;; ptr++) Line 4380  for (;; ptr++)
             case ESC_P:              case ESC_P:
               {                {
               BOOL negated;                BOOL negated;
              int pdata;              unsigned int ptype = 0, pdata = 0;
              int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);              if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
              if (ptype < 0) goto FAILED;                goto FAILED;
              xclass = TRUE;              *class_uchardata++ = ((escape == ESC_p) != negated)?
              *class_uchardata++ = ((-c == ESC_p) != negated)? 
                 XCL_PROP : XCL_NOTPROP;                  XCL_PROP : XCL_NOTPROP;
               *class_uchardata++ = ptype;                *class_uchardata++ = ptype;
               *class_uchardata++ = pdata;                *class_uchardata++ = pdata;
Line 4275  for (;; ptr++) Line 4402  for (;; ptr++)
               goto FAILED;                goto FAILED;
               }                }
             class_has_8bitchar--;    /* Undo the speculative increase. */              class_has_8bitchar--;    /* Undo the speculative increase. */
            class_single_char -= 2;  /* Undo the speculative increase. */            class_one_char -= 2;     /* Undo the speculative increase. */
             c = *ptr;                /* Get the final character and fall through */              c = *ptr;                /* Get the final character and fall through */
             break;              break;
             }              }
           }            }
   
        /* Fall through if we have a single character (c >= 0). This may be        /* Fall through if the escape just defined a single character (c >= 0).
        greater than 256. */        This may be greater than 256. */
   
           escape = 0;
   
         }   /* End of backslash handling */          }   /* End of backslash handling */
   
      /* A single character may be followed by '-' to form a range. However,      /* A character may be followed by '-' to form a range. However, Perl does
      Perl does not permit ']' to be the end of the range. A '-' character      not permit ']' to be the end of the range. A '-' character at the end is
      at the end is treated as a literal. Perl ignores orphaned \E sequences      treated as a literal. Perl ignores orphaned \E sequences entirely. The
      entirely. The code for handling \Q and \E is messy. */      code for handling \Q and \E is messy. */
   
       CHECK_RANGE:        CHECK_RANGE:
       while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)        while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
Line 4297  for (;; ptr++) Line 4426  for (;; ptr++)
         inescq = FALSE;          inescq = FALSE;
         ptr += 2;          ptr += 2;
         }          }
   
       oldptr = ptr;        oldptr = ptr;
   
      /* Remember \r or \n */      /* Remember if \r or \n were explicitly used */
   
       if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;        if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
   
Line 4308  for (;; ptr++) Line 4436  for (;; ptr++)
   
       if (!inescq && ptr[1] == CHAR_MINUS)        if (!inescq && ptr[1] == CHAR_MINUS)
         {          {
        int d;        pcre_uint32 d;
         ptr += 2;          ptr += 2;
         while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;          while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;
   
Line 4324  for (;; ptr++) Line 4452  for (;; ptr++)
           break;            break;
           }            }
   
        if (*ptr == 0 || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET))        /* Minus (hyphen) at the end of a class is treated as a literal, so put
         back the pointer and jump to handle the character that preceded it. */
 
         if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET))
           {            {
           ptr = oldptr;            ptr = oldptr;
          goto LONE_SINGLE_CHARACTER;          goto CLASS_SINGLE_CHARACTER;
           }            }
   
           /* Otherwise, we have a potential range; pick up the next character */
   
 #ifdef SUPPORT_UTF  #ifdef SUPPORT_UTF
         if (utf)          if (utf)
           {                           /* Braces are required because the */            {                           /* Braces are required because the */
Line 4345  for (;; ptr++) Line 4478  for (;; ptr++)
   
         if (!inescq && d == CHAR_BACKSLASH)          if (!inescq && d == CHAR_BACKSLASH)
           {            {
          d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE);          int descape;
           descape = check_escape(&ptr, &d, errorcodeptr, cd->bracount, options, TRUE);
           if (*errorcodeptr != 0) goto FAILED;            if (*errorcodeptr != 0) goto FAILED;
   
          /* \b is backspace; any other special means the '-' was literal */          /* \b is backspace; any other special means the '-' was literal. */
   
          if (d < 0)          if (descape != 0)
             {              {
            if (d == -ESC_b) d = CHAR_BS; else            if (descape == ESC_b) d = CHAR_BS; else
               {                {
               ptr = oldptr;                ptr = oldptr;
              goto LONE_SINGLE_CHARACTER;  /* A few lines below */              goto CLASS_SINGLE_CHARACTER;  /* A few lines below */
               }                }
             }              }
           }            }
   
         /* Check that the two values are in the correct order. Optimize          /* Check that the two values are in the correct order. Optimize
        one-character ranges */        one-character ranges. */
   
         if (d < c)          if (d < c)
           {            {
           *errorcodeptr = ERR8;            *errorcodeptr = ERR8;
           goto FAILED;            goto FAILED;
           }            }
           if (d == c) goto CLASS_SINGLE_CHARACTER;  /* A few lines below */
   
        if (d == c) goto LONE_SINGLE_CHARACTER;  /* A few lines below */        /* We have found a character range, so single character optimizations
         cannot be done anymore. Any value greater than 1 indicates that there
         is more than one character. */
   
        /* Remember \r or \n */        class_one_char = 2;
   
           /* Remember an explicit \r or \n, and add the range to the class. */
   
         if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;          if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
   
        /* Since we found a character range, single character optimizations        class_has_8bitchar +=
        cannot be done anymore. */          add_to_class(classbits, &class_uchardata, options, cd, c, d);
        class_single_char = 2; 
   
        /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless        continue;   /* Go get the next char in the class */
        matching, we have to use an XCLASS with extra data items. Caseless        }
        matching for characters > 127 is available only if UCP support is 
        available. */ 
   
#if defined SUPPORT_UTF && !(defined COMPILE_PCRE8)      /* Handle a single character - we can get here for a normal non-escape
        if ((d > 255) || (utf && ((options & PCRE_CASELESS) != 0 && d > 127)))      char, or after \ that introduces a single character or for an apparent
#elif defined  SUPPORT_UTF      range that isn't. Only the value 1 matters for class_one_char, so don't
        if (utf && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))      increase it if it is already 2 or more ... just in case there's a class
#elif !(defined COMPILE_PCRE8)      with a zillion characters in it. */
        if (d > 255) 
#endif 
#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) 
          { 
          xclass = TRUE; 
   
          /* With UCP support, we can find the other case equivalents of      CLASS_SINGLE_CHARACTER:
          the relevant characters. There may be several ranges. Optimize how      if (class_one_char < 2) class_one_char++;
          they fit with the basic range. */ 
   
#ifdef SUPPORT_UCP      /* If class_one_char is 1, we have the first single character in the
#ifndef COMPILE_PCRE8      class, and there have been no prior ranges, or XCLASS items generated by
          if (utf && (options & PCRE_CASELESS) != 0)      escapes. If this is the final character in the class, we can optimize by
#else      turning the item into a 1-character OP_CHAR[I] if it's positive, or
          if ((options & PCRE_CASELESS) != 0)      OP_NOT[I] if it's negative. In the positive case, it can cause firstchar
#endif      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
            unsigned int occ, ocd;      previous value for reinstating. */
            unsigned int cc = c; 
            unsigned int origd = d; 
            while (get_othercase_range(&cc, origd, &occ, &ocd)) 
              { 
              if (occ >= (unsigned int)c && 
                  ocd <= (unsigned int)d) 
                continue;                          /* Skip embedded ranges */ 
   
              if (occ < (unsigned int)c  &&      if (class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
                  ocd >= (unsigned int)c - 1)      /* Extend the basic range */        {
                {                                  /* if there is overlap,   */        ptr++;
                c = occ;                           /* noting that if occ < c */        zeroreqchar = reqchar;
                continue;                          /* we can't have ocd > d  */        zeroreqcharflags = reqcharflags;
                }                                  /* because a subrange is  */ 
              if (ocd > (unsigned int)d && 
                  occ <= (unsigned int)d + 1)      /* always shorter than    */ 
                {                                  /* the basic range.       */ 
                d = ocd; 
                continue; 
                } 
   
              if (occ == ocd)        if (negate_class)
                {          {
                *class_uchardata++ = XCL_SINGLE;#ifdef SUPPORT_UCP
                }          int d;
              else 
                { 
                *class_uchardata++ = XCL_RANGE; 
                class_uchardata += PRIV(ord2utf)(occ, class_uchardata); 
                } 
              class_uchardata += PRIV(ord2utf)(ocd, class_uchardata); 
              } 
            } 
#endif  /* SUPPORT_UCP */ 
 
          /* Now record the original range, possibly modified for UCP caseless 
          overlapping ranges. */ 
 
          *class_uchardata++ = XCL_RANGE; 
#ifdef SUPPORT_UTF 
#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  #endif
#else /* SUPPORT_UTF */          if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
          *class_uchardata++ = c;          zerofirstchar = firstchar;
          *class_uchardata++ = d;          zerofirstcharflags = firstcharflags;
#endif /* SUPPORT_UTF */ 
   
          /* With UCP support, we are done. Without UCP support, there is no          /* For caseless UTF-8 mode when UCP support is available, check
          caseless matching for UTF characters > 127; we can use the bit map          whether this character has more than one other case. If so, generate
          for the smaller ones. As for 16 bit characters without UTF, we          a special OP_NOTPROP item instead of OP_NOTI. */
          can still use  */ 
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
#ifndef COMPILE_PCRE8          if (utf && (options & PCRE_CASELESS) != 0 &&
          if (utf)              (d = UCD_CASESET(c)) != 0)
#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;            *code++ = OP_NOTPROP;
            /* Adjust upper limit and fall through to set up the map */            *code++ = PT_CLIST;
            d = 127;            *code++ = d;
             }              }
           else            else
            {#endif
            if (c > 255) continue;          /* Char has only one other case, or UCP not available */
            /* 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 */ 
          d = 127; 
#else 
          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_UTF || !COMPILE_PCRE8 */ 
   
         /* We use the bit map for 8 bit mode, or when the characters fall  
         partially or entirely to [0-255] ([0-127] for UCP) ranges. */  
   
         class_has_8bitchar = 1;  
   
         /* We can save a bit of time by skipping this in the pre-compile. */  
   
         if (lengthptr == NULL) for (; c <= d; c++)  
           {  
           classbits[c/8] |= (1 << (c&7));  
           if ((options & PCRE_CASELESS) != 0)  
             {              {
            int uc = cd->fcc[c]; /* flip case */            *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;
            classbits[uc/8] |= (1 << (uc&7));#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
             if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
               code += PRIV(ord2utf)(c, code);
             else
 #endif
               *code++ = c;
             }              }
           }  
   
        continue;   /* Go get the next char in the class */          /* We are finished with this character class */
        } 
   
      /* Handle a lone single character - we can get here for a normal          goto END_CLASS;
      non-escape char, or after \ that introduces a single character or for an 
      apparent range that isn't. */ 
 
      LONE_SINGLE_CHARACTER: 
 
      /* Only the value of 1 matters for class_single_char. */ 
 
      if (class_single_char < 2) class_single_char++; 
 
      /* If class_charcount is 1, we saw precisely one character. As long as 
      there was no use of \p or \P, in other words, no use of any XCLASS 
      features, we can optimize. 
 
      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. 
      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. */ 
 
      if (class_single_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) 
        { 
        ptr++; 
        zeroreqchar = reqchar; 
 
        if (negate_class) 
          { 
          if (firstchar == REQ_UNSET) firstchar = REQ_NONE; 
          zerofirstchar = firstchar; 
          *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT; 
#ifdef SUPPORT_UTF 
          if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) 
            code += PRIV(ord2utf)(c, code); 
          else 
#endif 
            *code++ = c; 
          goto NOT_CHAR; 
           }            }
   
         /* For a single, positive character, get the value into mcbuffer, and          /* For a single, positive character, get the value into mcbuffer, and
         then we can handle this with the normal one-character code. */          then we can handle this with the normal one-character code. */
   
#ifdef SUPPORT_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
         if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)          if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
           mclength = PRIV(ord2utf)(c, mcbuffer);            mclength = PRIV(ord2utf)(c, mcbuffer);
         else          else
Line 4578  for (;; ptr++) Line 4599  for (;; ptr++)
         goto ONE_CHAR;          goto ONE_CHAR;
         }       /* End of 1-char optimization */          }       /* End of 1-char optimization */
   
      /* Handle a character that cannot go in the bit map. */      /* There is more than one character in the class, or an XCLASS item
       has been generated. Add this character to the class. */
   
#if defined SUPPORT_UTF && !(defined COMPILE_PCRE8)      class_has_8bitchar +=
      if ((c > 255) || (utf && ((options & PCRE_CASELESS) != 0 && c > 127)))        add_to_class(classbits, &class_uchardata, options, cd, c, c);
#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 COMPILE_PCRE8 
        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; 
          if ((int)(othercase = UCD_OTHERCASE(c)) != c) 
            { 
            *class_uchardata++ = XCL_SINGLE; 
            class_uchardata += PRIV(ord2utf)(othercase, class_uchardata); 
            } 
          } 
#endif  /* SUPPORT_UCP */ 
 
        } 
      else 
#endif  /* SUPPORT_UTF || COMPILE_PCRE16 */ 
 
      /* Handle a single-byte character */ 
        { 
        class_has_8bitchar = 1; 
        classbits[c/8] |= (1 << (c&7)); 
        if ((options & PCRE_CASELESS) != 0) 
          { 
          c = cd->fcc[c]; /* flip case */ 
          classbits[c/8] |= (1 << (c&7)); 
          } 
        } 
       }        }
   
     /* Loop until ']' reached. This "while" is the end of the "do" far above.      /* Loop until ']' reached. This "while" is the end of the "do" far above.
     If we are at the end of an internal nested string, revert to the outer      If we are at the end of an internal nested string, revert to the outer
     string. */      string. */
   
    while (((c = *(++ptr)) != 0 ||    while (((c = *(++ptr)) != CHAR_NULL ||
            (nestptr != NULL &&             (nestptr != NULL &&
             (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != 0)) &&             (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != CHAR_NULL)) &&
            (c != CHAR_RIGHT_SQUARE_BRACKET || inescq));             (c != CHAR_RIGHT_SQUARE_BRACKET || inescq));
   
     /* Check for missing terminating ']' */      /* Check for missing terminating ']' */
   
    if (c == 0)    if (c == CHAR_NULL)
       {        {
       *errorcodeptr = ERR6;        *errorcodeptr = ERR6;
       goto FAILED;        goto FAILED;
       }        }
   
       /* We will need an XCLASS if data has been placed in class_uchardata. In
       the second phase this is a sufficient test. However, in the pre-compile
       phase, class_uchardata gets emptied to prevent workspace overflow, so it
       only if the very last character in the class needs XCLASS will it contain
       anything at this point. For this reason, xclass gets set TRUE above when
       uchar_classdata is emptied, and that's why this code is the way it is here
       instead of just doing a test on class_uchardata below. */
   
   #if defined SUPPORT_UTF || !defined COMPILE_PCRE8
       if (class_uchardata > class_uchardata_base) xclass = TRUE;
   #endif
   
     /* If this is the first thing in the branch, there can be no first char      /* If this is the first thing in the branch, there can be no first char
     setting, whatever the repeat count. Any reqchar setting must remain      setting, whatever the repeat count. Any reqchar setting must remain
     unchanged after any kind of repeat. */      unchanged after any kind of repeat. */
   
    if (firstchar == REQ_UNSET) firstchar = REQ_NONE;    if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
     zerofirstchar = firstchar;      zerofirstchar = firstchar;
       zerofirstcharflags = firstcharflags;
     zeroreqchar = reqchar;      zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
   
     /* 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
Line 4716  for (;; ptr++) Line 4699  for (;; ptr++)
       memcpy(code, classbits, 32);        memcpy(code, classbits, 32);
       }        }
     code += 32 / sizeof(pcre_uchar);      code += 32 / sizeof(pcre_uchar);
    NOT_CHAR:
     END_CLASS:
     break;      break;
   
   
Line 4754  for (;; ptr++) Line 4738  for (;; ptr++)
     if (repeat_min == 0)      if (repeat_min == 0)
       {        {
       firstchar = zerofirstchar;    /* Adjust for zero repeat */        firstchar = zerofirstchar;    /* Adjust for zero repeat */
         firstcharflags = zerofirstcharflags;
       reqchar = zeroreqchar;        /* Ditto */        reqchar = zeroreqchar;        /* Ditto */
         reqcharflags = zeroreqcharflags;
       }        }
   
     /* Remember whether this is a variable length repeat */      /* Remember whether this is a variable length repeat */
Line 4840  for (;; ptr++) Line 4826  for (;; ptr++)
       hold the length of the character in bytes, plus UTF_LENGTH to flag that        hold the length of the character in bytes, plus UTF_LENGTH to flag that
       it's a length rather than a small character. */        it's a length rather than a small character. */
   
#ifdef SUPPORT_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
       if (utf && NOT_FIRSTCHAR(code[-1]))        if (utf && NOT_FIRSTCHAR(code[-1]))
         {          {
         pcre_uchar *lastchar = code - 1;          pcre_uchar *lastchar = code - 1;
Line 4857  for (;; ptr++) Line 4843  for (;; ptr++)
         {          {
         c = code[-1];          c = code[-1];
         if (*previous <= OP_CHARI && repeat_min > 1)          if (*previous <= OP_CHARI && repeat_min > 1)
          reqchar = c | req_caseopt | cd->req_varyopt;          {
           reqchar = c;
           reqcharflags = 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 4914  for (;; ptr++) Line 4903  for (;; ptr++)
   
       if (repeat_max == 0) goto END_REPEAT;        if (repeat_max == 0) goto END_REPEAT;
   
       /*--------------------------------------------------------------------*/  
       /* This code is obsolete from release 8.00; the restriction was finally  
       removed: */  
   
       /* All real repeats make it impossible to handle partial matching (maybe  
       one day we will be able to remove this restriction). */  
   
       /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */  
       /*--------------------------------------------------------------------*/  
   
       /* Combine the op_type with the repeat_type */        /* Combine the op_type with the repeat_type */
   
       repeat_type += op_type;        repeat_type += op_type;
Line 4976  for (;; ptr++) Line 4955  for (;; ptr++)
   
         if (repeat_max < 0)          if (repeat_max < 0)
           {            {
#ifdef SUPPORT_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
           if (utf && (c & UTF_LENGTH) != 0)            if (utf && (c & UTF_LENGTH) != 0)
             {              {
             memcpy(code, utf_chars, IN_UCHARS(c & 7));              memcpy(code, utf_chars, IN_UCHARS(c & 7));
Line 5001  for (;; ptr++) Line 4980  for (;; ptr++)
   
         else if (repeat_max != repeat_min)          else if (repeat_max != repeat_min)
           {            {
#ifdef SUPPORT_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
           if (utf && (c & UTF_LENGTH) != 0)            if (utf && (c & UTF_LENGTH) != 0)
             {              {
             memcpy(code, utf_chars, IN_UCHARS(c & 7));              memcpy(code, utf_chars, IN_UCHARS(c & 7));
Line 5031  for (;; ptr++) Line 5010  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_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
       if (utf && (c & UTF_LENGTH) != 0)        if (utf && (c & UTF_LENGTH) != 0)
         {          {
         memcpy(code, utf_chars, IN_UCHARS(c & 7));          memcpy(code, utf_chars, IN_UCHARS(c & 7));
Line 5070  for (;; ptr++) Line 5049  for (;; ptr++)
         goto END_REPEAT;          goto END_REPEAT;
         }          }
   
       /*--------------------------------------------------------------------*/  
       /* This code is obsolete from release 8.00; the restriction was finally  
       removed: */  
   
       /* All real repeats make it impossible to handle partial matching (maybe  
       one day we will be able to remove this restriction). */  
   
       /* if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; */  
       /*--------------------------------------------------------------------*/  
   
       if (repeat_min == 0 && repeat_max == -1)        if (repeat_min == 0 && repeat_max == -1)
         *code++ = OP_CRSTAR + repeat_type;          *code++ = OP_CRSTAR + repeat_type;
       else if (repeat_min == 1 && repeat_max == -1)        else if (repeat_min == 1 && repeat_max == -1)
Line 5239  for (;; ptr++) Line 5208  for (;; ptr++)
   
           else            else
             {              {
            if (groupsetfirstchar && reqchar < 0) reqchar = firstchar;            if (groupsetfirstchar && reqcharflags < 0)
               {
               reqchar = firstchar;
               reqcharflags = firstcharflags;
               }
   
             for (i = 1; i < repeat_min; i++)              for (i = 1; i < repeat_min; i++)
               {                {
Line 5614  for (;; ptr++) Line 5587  for (;; ptr++)
       if (*ptr == CHAR_COLON)        if (*ptr == CHAR_COLON)
         {          {
         arg = ++ptr;          arg = ++ptr;
        while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;        while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
         arglen = (int)(ptr - arg);          arglen = (int)(ptr - arg);
        if (arglen > (int)MAX_MARK)        if ((unsigned int)arglen > MAX_MARK)
           {            {
           *errorcodeptr = ERR75;            *errorcodeptr = ERR75;
           goto FAILED;            goto FAILED;
Line 5636  for (;; ptr++) Line 5609  for (;; ptr++)
         if (namelen == verbs[i].len &&          if (namelen == verbs[i].len &&
             STRNCMP_UC_C8(name, vn, namelen) == 0)              STRNCMP_UC_C8(name, vn, namelen) == 0)
           {            {
             int setverb;
   
           /* Check for open captures before ACCEPT and convert it to            /* Check for open captures before ACCEPT and convert it to
           ASSERT_ACCEPT if in an assertion. */            ASSERT_ACCEPT if in an assertion. */
   
Line 5653  for (;; ptr++) Line 5628  for (;; ptr++)
               *code++ = OP_CLOSE;                *code++ = OP_CLOSE;
               PUT2INC(code, 0, oc->number);                PUT2INC(code, 0, oc->number);
               }                }
            *code++ = (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;            setverb = *code++ =
               (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
   
             /* Do not set firstchar after *ACCEPT */              /* Do not set firstchar after *ACCEPT */
            if (firstchar == REQ_UNSET) firstchar = REQ_NONE;            if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
             }              }
   
           /* Handle other cases with/without an argument */            /* Handle other cases with/without an argument */
Line 5668  for (;; ptr++) Line 5644  for (;; ptr++)
               *errorcodeptr = ERR66;                *errorcodeptr = ERR66;
               goto FAILED;                goto FAILED;
               }                }
            *code = verbs[i].op;            setverb = *code++ = verbs[i].op;
            if (*code++ == OP_THEN) cd->external_flags |= PCRE_HASTHEN; 
             }              }
   
           else            else
Line 5679  for (;; ptr++) Line 5654  for (;; ptr++)
               *errorcodeptr = ERR59;                *errorcodeptr = ERR59;
               goto FAILED;                goto FAILED;
               }                }
            *code = verbs[i].op_arg;            setverb = *code++ = verbs[i].op_arg;
            if (*code++ == OP_THEN_ARG) cd->external_flags |= PCRE_HASTHEN; 
             *code++ = arglen;              *code++ = arglen;
             memcpy(code, arg, IN_UCHARS(arglen));              memcpy(code, arg, IN_UCHARS(arglen));
             code += arglen;              code += arglen;
             *code++ = 0;              *code++ = 0;
             }              }
   
             switch (setverb)
               {
               case OP_THEN:
               case OP_THEN_ARG:
               cd->external_flags |= PCRE_HASTHEN;
               break;
   
               case OP_PRUNE:
               case OP_PRUNE_ARG:
               case OP_SKIP:
               case OP_SKIP_ARG:
               cd->had_pruneorskip = TRUE;
               break;
               }
   
           break;  /* Found verb, exit loop */            break;  /* Found verb, exit loop */
           }            }
   
Line 5712  for (;; ptr++) Line 5701  for (;; ptr++)
         {          {
         case CHAR_NUMBER_SIGN:                 /* Comment; skip to ket */          case CHAR_NUMBER_SIGN:                 /* Comment; skip to ket */
         ptr++;          ptr++;
        while (*ptr != 0 && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;        while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
        if (*ptr == 0)        if (*ptr == CHAR_NULL)
           {            {
           *errorcodeptr = ERR18;            *errorcodeptr = ERR18;
           goto FAILED;            goto FAILED;
Line 5736  for (;; ptr++) Line 5725  for (;; ptr++)
         /* ------------------------------------------------------------ */          /* ------------------------------------------------------------ */
         case CHAR_LEFT_PARENTHESIS:          case CHAR_LEFT_PARENTHESIS:
         bravalue = OP_COND;       /* Conditional group */          bravalue = OP_COND;       /* Conditional group */
           tempptr = ptr;
   
         /* A condition can be an assertion, a number (referring to a numbered          /* A condition can be an assertion, a number (referring to a numbered
         group), a name (referring to a named group), or 'R', referring to          group), a name (referring to a named group), or 'R', referring to
Line 5748  for (;; ptr++) Line 5738  for (;; ptr++)
         be the recursive thing or the name 'R' (and similarly for 'R' followed          be the recursive thing or the name 'R' (and similarly for 'R' followed
         by digits), and (b) a number could be a name that consists of digits.          by digits), and (b) a number could be a name that consists of digits.
         In both cases, we look for a name first; if not found, we try the other          In both cases, we look for a name first; if not found, we try the other
        cases. */        cases.
   
           For compatibility with auto-callouts, we allow a callout to be
           specified before a condition that is an assertion. First, check for the
           syntax of a callout; if found, adjust the temporary pointer that is
           used to check for an assertion condition. That's all that is needed! */
   
           if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C)
             {
             for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
             if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
               tempptr += i + 1;
             }
   
         /* For conditions that are assertions, check the syntax, and then exit          /* For conditions that are assertions, check the syntax, and then exit
         the switch. This will take control down to where bracketed groups,          the switch. This will take control down to where bracketed groups,
         including assertions, are processed. */          including assertions, are processed. */
   
        if (ptr[1] == CHAR_QUESTION_MARK && (ptr[2] == CHAR_EQUALS_SIGN ||        if (tempptr[1] == CHAR_QUESTION_MARK &&
            ptr[2] == CHAR_EXCLAMATION_MARK || ptr[2] == CHAR_LESS_THAN_SIGN))              (tempptr[2] == CHAR_EQUALS_SIGN ||
                tempptr[2] == CHAR_EXCLAMATION_MARK ||
                tempptr[2] == CHAR_LESS_THAN_SIGN))
           break;            break;
   
         /* Most other conditions use OP_CREF (a couple change to OP_RREF          /* Most other conditions use OP_CREF (a couple change to OP_RREF
Line 5789  for (;; ptr++) Line 5793  for (;; ptr++)
           }            }
         else          else
           {            {
          terminator = 0;          terminator = CHAR_NULL;
           if (ptr[1] == CHAR_MINUS || ptr[1] == CHAR_PLUS) refsign = *(++ptr);            if (ptr[1] == CHAR_MINUS || ptr[1] == CHAR_PLUS) refsign = *(++ptr);
           }            }
   
Line 5809  for (;; ptr++) Line 5813  for (;; ptr++)
         while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0)          while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0)
           {            {
           if (recno >= 0)            if (recno >= 0)
            recno = (IS_DIGIT(*ptr))? recno * 10 + *ptr - CHAR_0 : -1;            recno = (IS_DIGIT(*ptr))? recno * 10 + (int)(*ptr - CHAR_0) : -1;
           ptr++;            ptr++;
           }            }
         namelen = (int)(ptr - name);          namelen = (int)(ptr - name);
   
        if ((terminator > 0 && *ptr++ != terminator) ||        if ((terminator > 0 && *ptr++ != (pcre_uchar)terminator) ||
             *ptr++ != CHAR_RIGHT_PARENTHESIS)              *ptr++ != CHAR_RIGHT_PARENTHESIS)
           {            {
           ptr--;      /* Error offset */            ptr--;      /* Error offset */
Line 5879  for (;; ptr++) Line 5883  for (;; ptr++)
           code[1+LINK_SIZE]++;            code[1+LINK_SIZE]++;
           }            }
   
        /* If terminator == 0 it means that the name followed directly after        /* If terminator == CHAR_NULL it means that the name followed directly
        the opening parenthesis [e.g. (?(abc)...] and in this case there are        after the opening parenthesis [e.g. (?(abc)...] and in this case there
        some further alternatives to try. For the cases where terminator != 0        are some further alternatives to try. For the cases where terminator !=
        [things like (?(<name>... or (?('name')... or (?(R&name)... ] we have        0 [things like (?(<name>... or (?('name')... or (?(R&name)... ] we have
         now checked all the possibilities, so give an error. */          now checked all the possibilities, so give an error. */
   
        else if (terminator != 0)        else if (terminator != CHAR_NULL)
           {            {
           *errorcodeptr = ERR15;            *errorcodeptr = ERR15;
           goto FAILED;            goto FAILED;
Line 6054  for (;; ptr++) Line 6058  for (;; ptr++)
   
           if (lengthptr != NULL)            if (lengthptr != NULL)
             {              {
            if (*ptr != terminator)            if (*ptr != (pcre_uchar)terminator)
               {                {
               *errorcodeptr = ERR42;                *errorcodeptr = ERR42;
               goto FAILED;                goto FAILED;
Line 6196  for (;; ptr++) Line 6200  for (;; ptr++)
             *errorcodeptr = ERR62;              *errorcodeptr = ERR62;
             goto FAILED;              goto FAILED;
             }              }
          if (*ptr != terminator)          if (*ptr != (pcre_uchar)terminator)
             {              {
             *errorcodeptr = ERR42;              *errorcodeptr = ERR42;
             goto FAILED;              goto FAILED;
Line 6302  for (;; ptr++) Line 6306  for (;; ptr++)
           while(IS_DIGIT(*ptr))            while(IS_DIGIT(*ptr))
             recno = recno * 10 + *ptr++ - CHAR_0;              recno = recno * 10 + *ptr++ - CHAR_0;
   
          if (*ptr != terminator)          if (*ptr != (pcre_uchar)terminator)
             {              {
             *errorcodeptr = ERR29;              *errorcodeptr = ERR29;
             goto FAILED;              goto FAILED;
Line 6406  for (;; ptr++) Line 6410  for (;; ptr++)
   
         /* Can't determine a first byte now */          /* Can't determine a first byte now */
   
        if (firstchar == REQ_UNSET) firstchar = REQ_NONE;        if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
         continue;          continue;
   
   
Line 6540  for (;; ptr++) Line 6544  for (;; ptr++)
          cond_depth +           cond_depth +
            ((bravalue == OP_COND)?1:0),   /* Depth of condition subpatterns */             ((bravalue == OP_COND)?1:0),   /* Depth of condition subpatterns */
          &subfirstchar,                   /* For possible first char */           &subfirstchar,                   /* For possible first char */
            &subfirstcharflags,
          &subreqchar,                     /* For possible last char */           &subreqchar,                     /* For possible last char */
            &subreqcharflags,
          bcptr,                           /* Current branch chain */           bcptr,                           /* Current branch chain */
          cd,                              /* Tables block */           cd,                              /* Tables block */
          (lengthptr == NULL)? NULL :      /* Actual compile phase */           (lengthptr == NULL)? NULL :      /* Actual compile phase */
Line 6601  for (;; ptr++) Line 6607  for (;; ptr++)
           *errorcodeptr = ERR27;            *errorcodeptr = ERR27;
           goto FAILED;            goto FAILED;
           }            }
        if (condcount == 1) subfirstchar = subreqchar = REQ_NONE;        if (condcount == 1) subfirstcharflags = subreqcharflags = REQ_NONE;
         }          }
       }        }
   
Line 6650  for (;; ptr++) Line 6656  for (;; ptr++)
     back off. */      back off. */
   
     zeroreqchar = reqchar;      zeroreqchar = reqchar;
       zeroreqcharflags = reqcharflags;
     zerofirstchar = firstchar;      zerofirstchar = firstchar;
       zerofirstcharflags = firstcharflags;
     groupsetfirstchar = FALSE;      groupsetfirstchar = FALSE;
   
     if (bravalue >= OP_ONCE)      if (bravalue >= OP_ONCE)
Line 6661  for (;; ptr++) Line 6669  for (;; ptr++)
       no firstchar, 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 firstchar to "none". */        repeat forces firstchar to "none". */
   
      if (firstchar == REQ_UNSET)      if (firstcharflags == REQ_UNSET)
         {          {
        if (subfirstchar >= 0)        if (subfirstcharflags >= 0)
           {            {
           firstchar = subfirstchar;            firstchar = subfirstchar;
             firstcharflags = subfirstcharflags;
           groupsetfirstchar = TRUE;            groupsetfirstchar = TRUE;
           }            }
        else firstchar = REQ_NONE;        else firstcharflags = REQ_NONE;
        zerofirstchar = REQ_NONE;        zerofirstcharflags = REQ_NONE;
         }          }
   
       /* If firstchar was previously set, convert the subpattern's firstchar        /* If firstchar was previously set, convert the subpattern's firstchar
       into reqchar 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 (subfirstchar >= 0 && subreqchar < 0)      else if (subfirstcharflags >= 0 && subreqcharflags < 0)
        subreqchar = subfirstchar | tempreqvary;        {
         subreqchar = subfirstchar;
         subreqcharflags = subfirstcharflags | tempreqvary;
         }
   
       /* If the subpattern set a required byte (or set a first byte that isn't        /* If the subpattern set a required byte (or set a first byte that isn't
       really the first byte - see above), set it. */        really the first byte - see above), set it. */
   
      if (subreqchar >= 0) reqchar = subreqchar;      if (subreqcharflags >= 0)
         {
         reqchar = subreqchar;
         reqcharflags = subreqcharflags;
         }
       }        }
   
     /* For a forward assertion, we take the reqchar, if set. This can be      /* For a forward assertion, we take the reqchar, if set. This can be
Line 6693  for (;; ptr++) Line 6709  for (;; ptr++)
     of a firstchar. 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
     firstchar, looking for an asserted first char. */      firstchar, looking for an asserted first char. */
   
    else if (bravalue == OP_ASSERT && subreqchar >= 0) reqchar = subreqchar;    else if (bravalue == OP_ASSERT && subreqcharflags >= 0)
       {
       reqchar = subreqchar;
       reqcharflags = subreqcharflags;
       }
     break;     /* End of processing '(' */      break;     /* End of processing '(' */
   
   
Line 6701  for (;; ptr++) Line 6721  for (;; ptr++)
     /* Handle metasequences introduced by \. For ones like \d, the ESC_ values      /* Handle metasequences introduced by \. For ones like \d, the ESC_ values
     are arranged to be the negation of the corresponding OP_values in the      are arranged to be the negation of the corresponding OP_values in the
     default case when PCRE_UCP is not set. For the back references, the values      default case when PCRE_UCP is not set. For the back references, the values
    are ESC_REF plus the reference number. Only back references and those types    are negative the reference number. Only back references and those types
     that consume a character may be repeated. We can test for values between      that consume a character may be repeated. We can test for values between
     ESC_b and ESC_Z for the latter; this may have to change if any new ones are      ESC_b and ESC_Z for the latter; this may have to change if any new ones are
     ever created. */      ever created. */
   
     case CHAR_BACKSLASH:      case CHAR_BACKSLASH:
     tempptr = ptr;      tempptr = ptr;
    c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE);    escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, FALSE);
     if (*errorcodeptr != 0) goto FAILED;      if (*errorcodeptr != 0) goto FAILED;
   
    if (c < 0)    if (escape == 0)                  /* The escape coded a single character */
       c = ec;
     else
       {        {
      if (-c == ESC_Q)            /* Handle start of quoted string */      if (escape == ESC_Q)            /* Handle start of quoted string */
         {          {
         if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)          if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
           ptr += 2;               /* avoid empty string */            ptr += 2;               /* avoid empty string */
Line 6721  for (;; ptr++) Line 6743  for (;; ptr++)
         continue;          continue;
         }          }
   
      if (-c == ESC_E) continue;  /* Perl ignores an orphan \E */      if (escape == ESC_E) continue;  /* Perl ignores an orphan \E */
   
       /* For metasequences that actually match a character, we disable the        /* For metasequences that actually match a character, we disable the
       setting of a first character if it hasn't already been set. */        setting of a first character if it hasn't already been set. */
   
      if (firstchar == REQ_UNSET && -c > ESC_b && -c < ESC_Z)      if (firstcharflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z)
        firstchar = REQ_NONE;        firstcharflags = REQ_NONE;
   
       /* Set values to reset to if this is followed by a zero repeat. */        /* Set values to reset to if this is followed by a zero repeat. */
   
       zerofirstchar = firstchar;        zerofirstchar = firstchar;
         zerofirstcharflags = firstcharflags;
       zeroreqchar = reqchar;        zeroreqchar = reqchar;
         zeroreqcharflags = reqcharflags;
   
       /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'        /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'
       is a subroutine call by number (Oniguruma syntax). In fact, the value        is a subroutine call by number (Oniguruma syntax). In fact, the value
      -ESC_g is returned only for these cases. So we don't need to check for <      ESC_g is returned only for these cases. So we don't need to check for <
      or ' if the value is -ESC_g. For the Perl syntax \g{n} the value is      or ' if the value is ESC_g. For the Perl syntax \g{n} the value is
      -ESC_REF+n, and for the Perl syntax \g{name} the result is -ESC_k (as      -n, and for the Perl syntax \g{name} the result is ESC_k (as
       that is a synonym for a named back reference). */        that is a synonym for a named back reference). */
   
      if (-c == ESC_g)      if (escape == ESC_g)
         {          {
         const pcre_uchar *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 */
Line 6761  for (;; ptr++) Line 6785  for (;; ptr++)
         if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS)          if (ptr[1] != CHAR_PLUS && ptr[1] != CHAR_MINUS)
           {            {
           BOOL is_a_number = TRUE;            BOOL is_a_number = TRUE;
          for (p = ptr + 1; *p != 0 && *p != terminator; p++)          for (p = ptr + 1; *p != CHAR_NULL && *p != (pcre_uchar)terminator; p++)
             {              {
             if (!MAX_255(*p)) { is_a_number = FALSE; break; }              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_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 != (pcre_uchar)terminator)
             {              {
             *errorcodeptr = ERR57;              *errorcodeptr = ERR57;
             break;              break;
Line 6785  for (;; ptr++) Line 6809  for (;; ptr++)
   
         p = ptr + 2;          p = ptr + 2;
         while (IS_DIGIT(*p)) p++;          while (IS_DIGIT(*p)) p++;
        if (*p != terminator)        if (*p != (pcre_uchar)terminator)
           {            {
           *errorcodeptr = ERR57;            *errorcodeptr = ERR57;
           break;            break;
Line 6797  for (;; ptr++) Line 6821  for (;; ptr++)
       /* \k<name> or \k'name' is a back reference by name (Perl syntax).        /* \k<name> or \k'name' is a back reference by name (Perl syntax).
       We also support \k{name} (.NET syntax).  */        We also support \k{name} (.NET syntax).  */
   
      if (-c == ESC_k)      if (escape == ESC_k)
         {          {
         if ((ptr[1] != CHAR_LESS_THAN_SIGN &&          if ((ptr[1] != CHAR_LESS_THAN_SIGN &&
           ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))            ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))
Line 6816  for (;; ptr++) Line 6840  for (;; ptr++)
       not set to cope with cases like (?=(\w+))\1: which would otherwise set        not set to cope with cases like (?=(\w+))\1: which would otherwise set
       ':' later. */        ':' later. */
   
      if (-c >= ESC_REF)      if (escape < 0)
         {          {
         open_capitem *oc;          open_capitem *oc;
        recno = -c - ESC_REF;        recno = -escape;
   
         HANDLE_REFERENCE:    /* Come here from named backref handling */          HANDLE_REFERENCE:    /* Come here from named backref handling */
        if (firstchar == REQ_UNSET) firstchar = REQ_NONE;        if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
         previous = code;          previous = code;
         *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;          *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
         PUT2INC(code, 0, recno);          PUT2INC(code, 0, recno);
Line 6846  for (;; ptr++) Line 6870  for (;; ptr++)
       /* So are Unicode property matches, if supported. */        /* So are Unicode property matches, if supported. */
   
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
      else if (-c == ESC_P || -c == ESC_p)      else if (escape == ESC_P || escape == ESC_p)
         {          {
         BOOL negated;          BOOL negated;
        int pdata;        unsigned int ptype = 0, pdata = 0;
        int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);        if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
        if (ptype < 0) goto FAILED;          goto FAILED;
         previous = code;          previous = code;
        *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP;        *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
         *code++ = ptype;          *code++ = ptype;
         *code++ = pdata;          *code++ = pdata;
         }          }
Line 6862  for (;; ptr++) Line 6886  for (;; ptr++)
       /* If Unicode properties are not supported, \X, \P, and \p are not        /* If Unicode properties are not supported, \X, \P, and \p are not
       allowed. */        allowed. */
   
      else if (-c == ESC_X || -c == ESC_P || -c == ESC_p)      else if (escape == ESC_X || escape == ESC_P || escape == ESC_p)
         {          {
         *errorcodeptr = ERR45;          *errorcodeptr = ERR45;
         goto FAILED;          goto FAILED;
Line 6873  for (;; ptr++) Line 6897  for (;; ptr++)
       can obtain the OP value by negating the escape value in the default        can obtain the OP value by negating the escape value in the default
       situation when PCRE_UCP is not set. When it *is* set, we substitute        situation when PCRE_UCP is not set. When it *is* set, we substitute
       Unicode property tests. Note that \b and \B do a one-character        Unicode property tests. Note that \b and \B do a one-character
      lookbehind. */      lookbehind, and \A also behaves as if it does. */
   
       else        else
         {          {
        if ((-c == ESC_b || -c == ESC_B) && cd->max_lookbehind == 0)        if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) &&
              cd->max_lookbehind == 0)
           cd->max_lookbehind = 1;            cd->max_lookbehind = 1;
 #ifdef SUPPORT_UCP  #ifdef SUPPORT_UCP
        if (-c >= ESC_DU && -c <= ESC_wu)        if (escape >= ESC_DU && escape <= ESC_wu)
           {            {
           nestptr = ptr + 1;                   /* Where to resume */            nestptr = ptr + 1;                   /* Where to resume */
          ptr = substitutes[-c - ESC_DU] - 1;  /* Just before substitute */          ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
           }            }
         else          else
 #endif  #endif
Line 6891  for (;; ptr++) Line 6916  for (;; ptr++)
         so that it works in DFA mode and in lookbehinds. */          so that it works in DFA mode and in lookbehinds. */
   
           {            {
          previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;          previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
          *code++ = (!utf && c == -ESC_C)? OP_ALLANY : -c;          *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
           }            }
         }          }
       continue;        continue;
Line 6902  for (;; ptr++) Line 6927  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_UTF#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
     if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)      if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
       mclength = PRIV(ord2utf)(c, mcbuffer);        mclength = PRIV(ord2utf)(c, mcbuffer);
     else      else
Line 6935  for (;; ptr++) Line 6960  for (;; ptr++)
   
     ONE_CHAR:      ONE_CHAR:
     previous = code;      previous = code;
   
       /* For caseless UTF-8 mode when UCP support is available, check whether
       this character has more than one other case. If so, generate a special
       OP_PROP item instead of OP_CHARI. */
   
   #ifdef SUPPORT_UCP
       if (utf && (options & PCRE_CASELESS) != 0)
         {
         GETCHAR(c, mcbuffer);
         if ((c = UCD_CASESET(c)) != 0)
           {
           *code++ = OP_PROP;
           *code++ = PT_CLIST;
           *code++ = c;
           if (firstcharflags == REQ_UNSET) firstcharflags = zerofirstcharflags = REQ_NONE;
           break;
           }
         }
   #endif
   
       /* Caseful matches, or not one of the multicase characters. */
   
     *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR;      *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR;
     for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];      for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];
   
Line 6948  for (;; ptr++) Line 6995  for (;; ptr++)
     Otherwise, leave the firstchar 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 (firstchar == REQ_UNSET)    if (firstcharflags == REQ_UNSET)
       {        {
      zerofirstchar = REQ_NONE;      zerofirstcharflags = REQ_NONE;
       zeroreqchar = reqchar;        zeroreqchar = reqchar;
         zeroreqcharflags = reqcharflags;
   
       /* If the character is more than one byte long, we can set firstchar        /* 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. */
Line 6959  for (;; ptr++) Line 7007  for (;; ptr++)
       if (mclength == 1 || req_caseopt == 0)        if (mclength == 1 || req_caseopt == 0)
         {          {
         firstchar = mcbuffer[0] | req_caseopt;          firstchar = mcbuffer[0] | req_caseopt;
        if (mclength != 1) reqchar = code[-1] | cd->req_varyopt;        firstchar = mcbuffer[0];
         firstcharflags = req_caseopt;
 
         if (mclength != 1)
           {
           reqchar = code[-1];
           reqcharflags = cd->req_varyopt;
           }
         }          }
      else firstchar = reqchar = REQ_NONE;      else firstcharflags = reqcharflags = REQ_NONE;
       }        }
   
     /* firstchar was previously set; we can set reqchar only if the length is      /* firstchar was previously set; we can set reqchar only if the length is
Line 6970  for (;; ptr++) Line 7025  for (;; ptr++)
     else      else
       {        {
       zerofirstchar = firstchar;        zerofirstchar = firstchar;
         zerofirstcharflags = firstcharflags;
       zeroreqchar = reqchar;        zeroreqchar = reqchar;
         zeroreqcharflags = reqcharflags;
       if (mclength == 1 || req_caseopt == 0)        if (mclength == 1 || req_caseopt == 0)
        reqchar = code[-1] | req_caseopt | cd->req_varyopt;        {
         reqchar = code[-1];
         reqcharflags = req_caseopt | cd->req_varyopt;
         }
       }        }
   
     break;            /* End of literal character handling */      break;            /* End of literal character handling */
Line 6991  return FALSE; Line 7051  return FALSE;
   
   
   
   
 /*************************************************  /*************************************************
 *     Compile sequence of alternatives           *  *     Compile sequence of alternatives           *
 *************************************************/  *************************************************/
Line 7012  Arguments: Line 7071  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
  firstcharptr   place to put the first required character, or a negative number  firstcharptr    place to put the first required character
  reqcharptr     place to put the last required character, or a negative number  firstcharflagsptr place to put the first character flags, or a negative number
   reqcharptr     place to put the last required character
   reqcharflagsptr place to put the last required character flags, 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 7025  Returns:         TRUE on success Line 7086  Returns:         TRUE on success
 static BOOL  static BOOL
 compile_regex(int options, pcre_uchar **codeptr, const pcre_uchar **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, pcre_int32 *firstcharptr, pcre_int32 *reqcharptr,  int cond_depth,
   pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
   pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
   branch_chain *bcptr, compile_data *cd, int *lengthptr)    branch_chain *bcptr, compile_data *cd, int *lengthptr)
 {  {
 const pcre_uchar *ptr = *ptrptr;  const pcre_uchar *ptr = *ptrptr;
Line 7035  pcre_uchar *start_bracket = code; Line 7098  pcre_uchar *start_bracket = code;
 pcre_uchar *reverse_count = NULL;  pcre_uchar *reverse_count = NULL;
 open_capitem capitem;  open_capitem capitem;
 int capnumber = 0;  int capnumber = 0;
pcre_int32 firstchar, reqchar;pcre_uint32 firstchar, reqchar;
pcre_int32 branchfirstchar, branchreqchar;pcre_int32 firstcharflags, reqcharflags;
 pcre_uint32 branchfirstchar, branchreqchar;
 pcre_int32 branchfirstcharflags, branchreqcharflags;
 int length;  int length;
int orig_bracount;unsigned int orig_bracount;
int max_bracount;unsigned int max_bracount;
 branch_chain bc;  branch_chain bc;
   
 bc.outer = bcptr;  bc.outer = bcptr;
 bc.current_branch = code;  bc.current_branch = code;
   
firstchar = reqchar = REQ_UNSET;firstchar = reqchar = 0;
 firstcharflags = reqcharflags = REQ_UNSET;
   
 /* Accumulate the length for use in the pre-compile phase. Start with the  /* Accumulate the length for use in the pre-compile phase. Start with the
 length of the BRA and KET and any extra bytes that are required at the  length of the BRA and KET and any extra bytes that are required at the
Line 7105  for (;;) Line 7171  for (;;)
   into the length. */    into the length. */
   
   if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar,    if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar,
        &branchreqchar, &bc, cond_depth, cd,        &branchfirstcharflags, &branchreqchar, &branchreqcharflags, &bc,
        (lengthptr == NULL)? NULL : &length))        cond_depth, cd, (lengthptr == NULL)? NULL : &length))
     {      {
     *ptrptr = ptr;      *ptrptr = ptr;
     return FALSE;      return FALSE;
Line 7127  for (;;) Line 7193  for (;;)
     if (*last_branch != OP_ALT)      if (*last_branch != OP_ALT)
       {        {
       firstchar = branchfirstchar;        firstchar = branchfirstchar;
         firstcharflags = branchfirstcharflags;
       reqchar = branchreqchar;        reqchar = branchreqchar;
         reqcharflags = branchreqcharflags;
       }        }
   
     /* If this is not the first branch, the first char and reqchar have to      /* If this is not the first branch, the first char and reqchar have to
Line 7141  for (;;) Line 7209  for (;;)
       we have to abandon the firstchar for the regex, but if there was        we have to abandon the firstchar for the regex, but if there was
       previously no reqchar, it takes on the value of the old firstchar. */        previously no reqchar, it takes on the value of the old firstchar. */
   
      if (firstchar >= 0 && firstchar != branchfirstchar)      if (firstcharflags >= 0 &&
           (firstcharflags != branchfirstcharflags || firstchar != branchfirstchar))
         {          {
        if (reqchar < 0) reqchar = firstchar;        if (reqcharflags < 0)
        firstchar = REQ_NONE;          {
           reqchar = firstchar;
           reqcharflags = firstcharflags;
           }
         firstcharflags = REQ_NONE;
         }          }
   
       /* If we (now or from before) have no firstchar, a firstchar from the        /* If we (now or from before) have no firstchar, a firstchar from the
       branch becomes a reqchar if there isn't a branch reqchar. */        branch becomes a reqchar if there isn't a branch reqchar. */
   
      if (firstchar < 0 && branchfirstchar >= 0 && branchreqchar < 0)      if (firstcharflags < 0 && branchfirstcharflags >= 0 && branchreqcharflags < 0)
          branchreqchar = branchfirstchar;        {
         branchreqchar = branchfirstchar;
         branchreqcharflags = branchfirstcharflags;
         }
   
       /* Now ensure that the reqchars match */        /* Now ensure that the reqchars match */
   
      if ((reqchar & ~REQ_VARY) != (branchreqchar & ~REQ_VARY))      if (((reqcharflags & ~REQ_VARY) != (branchreqcharflags & ~REQ_VARY)) ||
        reqchar = REQ_NONE;          reqchar != branchreqchar)
      else reqchar |= branchreqchar;   /* To "or" REQ_VARY */        reqcharflags = REQ_NONE;
       else
         {
         reqchar = branchreqchar;
         reqcharflags |= branchreqcharflags; /* To "or" REQ_VARY */
         }
       }        }
   
     /* If lookbehind, check that this branch matches a fixed-length string, and      /* If lookbehind, check that this branch matches a fixed-length string, and
Line 7253  for (;;) Line 7334  for (;;)
     *codeptr = code;      *codeptr = code;
     *ptrptr = ptr;      *ptrptr = ptr;
     *firstcharptr = firstchar;      *firstcharptr = firstchar;
       *firstcharflagsptr = firstcharflags;
     *reqcharptr = reqchar;      *reqcharptr = reqchar;
       *reqcharflagsptr = reqcharflags;
     if (lengthptr != NULL)      if (lengthptr != NULL)
       {        {
       if (OFLOW_MAX - *lengthptr < length)        if (OFLOW_MAX - *lengthptr < length)
Line 7323  and the highest back reference was greater than or equ Line 7406  and the highest back reference was greater than or equ
 However, by keeping a bitmap of the first 31 back references, we can catch some  However, by keeping a bitmap of the first 31 back references, we can catch some
 of the more common cases more precisely.  of the more common cases more precisely.
   
   ... A second exception is when the .* appears inside an atomic group, because
   this prevents the number of characters it matches from being adjusted.
   
 Arguments:  Arguments:
   code           points to start of expression (the bracket)    code           points to start of expression (the bracket)
   bracket_map    a bitmap of which brackets we are inside while testing; this    bracket_map    a bitmap of which brackets we are inside while testing; this
                   handles up to substring 31; after that we just have to take                    handles up to substring 31; after that we just have to take
                   the less precise approach                    the less precise approach
  backref_map    the back reference bitmap  cd             points to the compile data block
   atomcount      atomic group level
   
 Returns:     TRUE or FALSE  Returns:     TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
 is_anchored(register const pcre_uchar *code, unsigned int bracket_map,  is_anchored(register const pcre_uchar *code, unsigned int bracket_map,
  unsigned int backref_map)  compile_data *cd, int atomcount)
 {  {
 do {  do {
    const pcre_uchar *scode = first_significant_code(     const pcre_uchar *scode = first_significant_code(
Line 7347  do { Line 7434  do {
    if (op == OP_BRA  || op == OP_BRAPOS ||     if (op == OP_BRA  || op == OP_BRAPOS ||
        op == OP_SBRA || op == OP_SBRAPOS)         op == OP_SBRA || op == OP_SBRAPOS)
      {       {
     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;     if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
    /* Capturing brackets */     /* Capturing brackets */
Line 7357  do { Line 7444  do {
      {       {
      int n = GET2(scode, 1+LINK_SIZE);       int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);       int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
     if (!is_anchored(scode, new_map, backref_map)) return FALSE;     if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE;
      }       }
   
   /* Other brackets */   /* Positive forward assertions and conditions */
   
   else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC ||   else if (op == OP_ASSERT || op == OP_COND)
            op == OP_COND) 
      {       {
     if (!is_anchored(scode, bracket_map, backref_map)) return FALSE;     if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
      /* Atomic groups */
   
      else if (op == OP_ONCE || op == OP_ONCE_NC)
        {
        if (!is_anchored(scode, bracket_map, cd, atomcount + 1))
          return FALSE;
        }
   
    /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and     /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
   it isn't in brackets that are or may be referenced. */   it isn't in brackets that are or may be referenced or inside an atomic
    group. */
   
    else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||     else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||
              op == OP_TYPEPOSSTAR))               op == OP_TYPEPOSSTAR))
      {       {
     if (scode[1] != OP_ALLANY || (bracket_map & backref_map) != 0)     if (scode[1] != OP_ALLANY || (bracket_map & cd->backref_map) != 0 ||
          atomcount > 0 || cd->had_pruneorskip)
        return FALSE;         return FALSE;
      }       }
   
    /* Check for explicit anchoring */     /* Check for explicit anchoring */
   
    else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;     else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;
   
    code += GET(code, 1);     code += GET(code, 1);
    }     }
 while (*code == OP_ALT);   /* Loop for each alternative */  while (*code == OP_ALT);   /* Loop for each alternative */
Line 7398  return TRUE; Line 7495  return TRUE;
 matching and for non-DOTALL patterns that start with .* (which must start at  matching and for non-DOTALL patterns that start with .* (which must start at
 the beginning or after \n). As in the case of is_anchored() (see above), we  the beginning or after \n). As in the case of is_anchored() (see above), we
 have to take account of back references to capturing brackets that contain .*  have to take account of back references to capturing brackets that contain .*
because in that case we can't make the assumption.because in that case we can't make the assumption. Also, the appearance of .*
 inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not
 count, because once again the assumption no longer holds.
   
 Arguments:  Arguments:
   code           points to start of expression (the bracket)    code           points to start of expression (the bracket)
   bracket_map    a bitmap of which brackets we are inside while testing; this    bracket_map    a bitmap of which brackets we are inside while testing; this
                   handles up to substring 31; after that we just have to take                    handles up to substring 31; after that we just have to take
                   the less precise approach                    the less precise approach
  backref_map    the back reference bitmap  cd             points to the compile data
   atomcount      atomic group level
   
 Returns:         TRUE or FALSE  Returns:         TRUE or FALSE
 */  */
   
 static BOOL  static BOOL
 is_startline(const pcre_uchar *code, unsigned int bracket_map,  is_startline(const pcre_uchar *code, unsigned int bracket_map,
  unsigned int backref_map)  compile_data *cd, int atomcount)
 {  {
 do {  do {
    const pcre_uchar *scode = first_significant_code(     const pcre_uchar *scode = first_significant_code(
Line 7438  do { Line 7538  do {
        return FALSE;         return FALSE;
   
        default:     /* Assertion */         default:     /* Assertion */
       if (!is_startline(scode, bracket_map, backref_map)) return FALSE;       if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
        do scode += GET(scode, 1); while (*scode == OP_ALT);         do scode += GET(scode, 1); while (*scode == OP_ALT);
        scode += 1 + LINK_SIZE;         scode += 1 + LINK_SIZE;
        break;         break;
Line 7452  do { Line 7552  do {
    if (op == OP_BRA  || op == OP_BRAPOS ||     if (op == OP_BRA  || op == OP_BRAPOS ||
        op == OP_SBRA || op == OP_SBRAPOS)         op == OP_SBRA || op == OP_SBRAPOS)
      {       {
     if (!is_startline(scode, bracket_map, backref_map)) return FALSE;     if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
    /* Capturing brackets */     /* Capturing brackets */
Line 7462  do { Line 7562  do {
      {       {
      int n = GET2(scode, 1+LINK_SIZE);       int n = GET2(scode, 1+LINK_SIZE);
      int new_map = bracket_map | ((n < 32)? (1 << n) : 1);       int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
     if (!is_startline(scode, new_map, backref_map)) return FALSE;     if (!is_startline(scode, new_map, cd, atomcount)) return FALSE;
      }       }
   
   /* Other brackets */   /* Positive forward assertions */
   
   else if (op == OP_ASSERT || op == OP_ONCE || op == OP_ONCE_NC)   else if (op == OP_ASSERT)
      {       {
     if (!is_startline(scode, bracket_map, backref_map)) return FALSE;     if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
      }       }
   
   /* .* means "start at start or after \n" if it isn't in brackets that   /* Atomic brackets */
   may be referenced. */ 
   
      else if (op == OP_ONCE || op == OP_ONCE_NC)
        {
        if (!is_startline(scode, bracket_map, cd, atomcount + 1)) return FALSE;
        }
   
      /* .* means "start at start or after \n" if it isn't in atomic brackets or
      brackets that may be referenced, as long as the pattern does not contain
      *PRUNE or *SKIP, because these break the feature. Consider, for example,
      /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the
      start of a line. */
   
    else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)     else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
      {       {
     if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;     if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 ||
          atomcount > 0 || cd->had_pruneorskip)
        return FALSE;
      }       }
   
   /* Check for explicit circumflex */   /* Check for explicit circumflex; anything else gives a FALSE result. Note
    in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC
    because the number of characters matched by .* cannot be adjusted inside
    them. */
   
    else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;     else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;
   
Line 7508  we return that char, otherwise -1. Line 7623  we return that char, otherwise -1.
   
 Arguments:  Arguments:
   code       points to start of expression (the bracket)    code       points to start of expression (the bracket)
     flags       points to the first char flags, or to REQ_NONE
   inassert   TRUE if in an assertion    inassert   TRUE if in an assertion
   
Returns:     -1 or the fixed first charReturns:     the fixed first char, or 0 with REQ_NONE in flags
 */  */
   
static intstatic pcre_uint32
find_firstassertedchar(const pcre_uchar *code, BOOL inassert)find_firstassertedchar(const pcre_uchar *code, pcre_int32 *flags,
   BOOL inassert)
 {  {
register int c = -1;register pcre_uint32 c = 0;
 int cflags = REQ_NONE;
 
 *flags = REQ_NONE;
 do {  do {
   int d;   pcre_uint32 d;
    int dflags;
    int xl = (*code == OP_CBRA || *code == OP_SCBRA ||     int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
              *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;               *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
    const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl,     const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl,
      TRUE);       TRUE);
   register int op = *scode;   register pcre_uchar op = *scode;
   
    switch(op)     switch(op)
      {       {
      default:       default:
     return -1;     return 0;
   
      case OP_BRA:       case OP_BRA:
      case OP_BRAPOS:       case OP_BRAPOS:
Line 7540  do { Line 7661  do {
      case OP_ONCE:       case OP_ONCE:
      case OP_ONCE_NC:       case OP_ONCE_NC:
      case OP_COND:       case OP_COND:
     if ((d = find_firstassertedchar(scode, op == OP_ASSERT)) < 0)     d = find_firstassertedchar(scode, &dflags, op == OP_ASSERT);
       return -1;     if (dflags < 0)
     if (c < 0) c = d; else if (c != d) return -1;       return 0;
      if (cflags < 0) { c = d; cflags = dflags; } else if (c != d || cflags != dflags) return 0;
      break;       break;
   
      case OP_EXACT:       case OP_EXACT:
Line 7553  do { Line 7675  do {
      case OP_PLUS:       case OP_PLUS:
      case OP_MINPLUS:       case OP_MINPLUS:
      case OP_POSPLUS:       case OP_POSPLUS:
     if (!inassert) return -1;     if (!inassert) return 0;
     if (c < 0) c = scode[1];     if (cflags < 0) { c = scode[1]; cflags = 0; }
       else if (c != scode[1]) return -1;       else if (c != scode[1]) return 0;
      break;       break;
   
      case OP_EXACTI:       case OP_EXACTI:
Line 7566  do { Line 7688  do {
      case OP_PLUSI:       case OP_PLUSI:
      case OP_MINPLUSI:       case OP_MINPLUSI:
      case OP_POSPLUSI:       case OP_POSPLUSI:
     if (!inassert) return -1;     if (!inassert) return 0;
     if (c < 0) c = scode[1] | REQ_CASELESS;     if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; }
       else if (c != scode[1]) return -1;       else if (c != scode[1]) return 0;
      break;       break;
      }       }
   
    code += GET(code, 1);     code += GET(code, 1);
    }     }
 while (*code == OP_ALT);  while (*code == OP_ALT);
   
   *flags = cflags;
 return c;  return c;
 }  }
   
Line 7602  Returns:        pointer to compiled data block, or NUL Line 7726  Returns:        pointer to compiled data block, or NUL
                 with errorptr and erroroffset set                  with errorptr and erroroffset set
 */  */
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
 pcre_compile(const char *pattern, int options, const char **errorptr,  pcre_compile(const char *pattern, int options, const char **errorptr,
   int *erroroffset, const unsigned char *tables)    int *erroroffset, const unsigned char *tables)
#else#elif defined COMPILE_PCRE16
 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
 pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr,  pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr,
   int *erroroffset, const unsigned char *tables)    int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE32
   PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
   pcre32_compile(PCRE_SPTR32 pattern, int options, const char **errorptr,
     int *erroroffset, const unsigned char *tables)
 #endif  #endif
 {  {
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
 return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);  return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
#else#elif defined COMPILE_PCRE16
 return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables);  return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
   #elif defined COMPILE_PCRE32
   return pcre32_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
 #endif  #endif
 }  }
   
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
 pcre_compile2(const char *pattern, int options, int *errorcodeptr,  pcre_compile2(const char *pattern, int options, int *errorcodeptr,
   const char **errorptr, int *erroroffset, const unsigned char *tables)    const char **errorptr, int *erroroffset, const unsigned char *tables)
#else#elif defined COMPILE_PCRE16
 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION  PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
 pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr,  pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr,
   const char **errorptr, int *erroroffset, const unsigned char *tables)    const char **errorptr, int *erroroffset, const unsigned char *tables)
   #elif defined COMPILE_PCRE32
   PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
   pcre32_compile2(PCRE_SPTR32 pattern, int options, int *errorcodeptr,
     const char **errorptr, int *erroroffset, const unsigned char *tables)
 #endif  #endif
 {  {
 REAL_PCRE *re;  REAL_PCRE *re;
 int length = 1;  /* For final END opcode */  int length = 1;  /* For final END opcode */
pcre_int32 firstchar, reqchar;pcre_int32 firstcharflags, reqcharflags;
 pcre_uint32 firstchar, reqchar;
 pcre_uint32 limit_match = PCRE_UINT32_MAX;
 pcre_uint32 limit_recursion = PCRE_UINT32_MAX;
 int newline;  int newline;
 int errorcode = 0;  int errorcode = 0;
 int skipatstart = 0;  int skipatstart = 0;
 BOOL utf;  BOOL utf;
   BOOL never_utf = FALSE;
 size_t size;  size_t size;
 pcre_uchar *code;  pcre_uchar *code;
 const pcre_uchar *codestart;  const pcre_uchar *codestart;
Line 7696  if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) Line 7834  if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0)
   goto PCRE_EARLY_ERROR_RETURN;    goto PCRE_EARLY_ERROR_RETURN;
   }    }
   
   /* If PCRE_NEVER_UTF is set, remember it. */
   
   if ((options & PCRE_NEVER_UTF) != 0) never_utf = TRUE;
   
 /* Check for global one-time settings at the start of the pattern, and remember  /* Check for global one-time settings at the start of the pattern, and remember
 the offset for later. */  the offset for later. */
   
   cd->external_flags = 0;   /* Initialize here for LIMIT_MATCH/RECURSION */
   
 while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
        ptr[skipatstart+1] == CHAR_ASTERISK)         ptr[skipatstart+1] == CHAR_ASTERISK)
   {    {
   int newnl = 0;    int newnl = 0;
   int newbsr = 0;    int newbsr = 0;
   
   /* For completeness and backward compatibility, (*UTFn) is supported in the
   relevant libraries, but (*UTF) is generic and always supported. Note that
   PCRE_UTF8 == PCRE_UTF16 == PCRE_UTF32. */
   
 #ifdef COMPILE_PCRE8  #ifdef COMPILE_PCRE8
  if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 5) == 0)  if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF8_RIGHTPAR, 5) == 0)
     { skipatstart += 7; options |= PCRE_UTF8; continue; }      { skipatstart += 7; options |= PCRE_UTF8; continue; }
 #endif  #endif
 #ifdef COMPILE_PCRE16  #ifdef COMPILE_PCRE16
  if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 6) == 0)  if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF16_RIGHTPAR, 6) == 0)
     { skipatstart += 8; options |= PCRE_UTF16; continue; }      { skipatstart += 8; options |= PCRE_UTF16; continue; }
 #endif  #endif
   #ifdef COMPILE_PCRE32
     if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF32_RIGHTPAR, 6) == 0)
       { skipatstart += 8; options |= PCRE_UTF32; continue; }
   #endif
   
     else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 4) == 0)
       { skipatstart += 6; options |= PCRE_UTF8; continue; }
   else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UCP_RIGHTPAR, 4) == 0)    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_UC_C8(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; }
   
     else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_MATCH_EQ, 12) == 0)
       {
       pcre_uint32 c = 0;
       int p = skipatstart + 14;
       while (isdigit(ptr[p]))
         {
         if (c > PCRE_UINT32_MAX / 10 - 1) break;   /* Integer overflow */
         c = c*10 + ptr[p++] - CHAR_0;
         }
       if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
       if (c < limit_match)
         {
         limit_match = c;
         cd->external_flags |= PCRE_MLSET;
         }
       skipatstart = p;
       continue;
       }
   
     else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_RECURSION_EQ, 16) == 0)
       {
       pcre_uint32 c = 0;
       int p = skipatstart + 18;
       while (isdigit(ptr[p]))
         {
         if (c > PCRE_UINT32_MAX / 10 - 1) break;   /* Integer overflow check */
         c = c*10 + ptr[p++] - CHAR_0;
         }
       if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
       if (c < limit_recursion)
         {
         limit_recursion = c;
         cd->external_flags |= PCRE_RLSET;
         }
       skipatstart = p;
       continue;
       }
   
   if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CR_RIGHTPAR, 3) == 0)    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_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3)  == 0)    else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3)  == 0)
Line 7741  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && Line 7934  while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
   else break;    else break;
   }    }
   
/* PCRE_UTF16 has the same value as PCRE_UTF8. *//* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */
 utf = (options & PCRE_UTF8) != 0;  utf = (options & PCRE_UTF8) != 0;
   if (utf && never_utf)
     {
     errorcode = ERR78;
     goto PCRE_EARLY_ERROR_RETURN2;
     }
   
 /* Can't support UTF 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 PRIV(valid_utf)() is a new feature, introduced in  return of an error code from PRIV(valid_utf)() is a new feature, introduced in
Line 7753  not used here. */ Line 7951  not used here. */
 if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 &&  if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 &&
      (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0)       (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0)
   {    {
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
   errorcode = ERR44;    errorcode = ERR44;
#else#elif defined COMPILE_PCRE16
   errorcode = ERR74;    errorcode = ERR74;
   #elif defined COMPILE_PCRE32
     errorcode = ERR77;
 #endif  #endif
   goto PCRE_EARLY_ERROR_RETURN2;    goto PCRE_EARLY_ERROR_RETURN2;
   }    }
Line 7863  cd->req_varyopt = 0; Line 8063  cd->req_varyopt = 0;
 cd->assert_depth = 0;  cd->assert_depth = 0;
 cd->max_lookbehind = 0;  cd->max_lookbehind = 0;
 cd->external_options = options;  cd->external_options = options;
 cd->external_flags = 0;  
 cd->open_caps = NULL;  cd->open_caps = NULL;
   
 /* Now do the pre-compile. On error, errorcode will be set non-zero, so we  /* Now do the pre-compile. On error, errorcode will be set non-zero, so we
Line 7876  ptr += skipatstart; Line 8075  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, &firstchar, &reqchar, NULL, cd, &length);  FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL,
   cd, &length);
 if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;  if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;
   
 DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,  DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
Line 7912  re->magic_number = MAGIC_NUMBER; Line 8112  re->magic_number = MAGIC_NUMBER;
 re->size = (int)size;  re->size = (int)size;
 re->options = cd->external_options;  re->options = cd->external_options;
 re->flags = cd->external_flags;  re->flags = cd->external_flags;
   re->limit_match = limit_match;
   re->limit_recursion = limit_recursion;
 re->first_char = 0;  re->first_char = 0;
 re->req_char = 0;  re->req_char = 0;
 re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar);  re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar);
Line 7920  re->name_count = cd->names_found; Line 8122  re->name_count = cd->names_found;
 re->ref_count = 0;  re->ref_count = 0;
 re->tables = (tables == PRIV(default_tables))? NULL : tables;  re->tables = (tables == PRIV(default_tables))? NULL : tables;
 re->nullpad = NULL;  re->nullpad = NULL;
   #ifdef COMPILE_PCRE32
   re->dummy = 0;
   #else
   re->dummy1 = re->dummy2 = re->dummy3 = 0;
   #endif
   
 /* The starting points of the name/number translation table and of the code are  /* The starting points of the name/number translation table and of the code are
 passed around in the compile data block. The start/end pattern and initial  passed around in the compile data block. The start/end pattern and initial
Line 7939  cd->start_code = codestart; Line 8146  cd->start_code = codestart;
 cd->hwm = (pcre_uchar *)(cd->start_workspace);  cd->hwm = (pcre_uchar *)(cd->start_workspace);
 cd->req_varyopt = 0;  cd->req_varyopt = 0;
 cd->had_accept = FALSE;  cd->had_accept = FALSE;
   cd->had_pruneorskip = FALSE;
 cd->check_lookbehind = FALSE;  cd->check_lookbehind = FALSE;
 cd->open_caps = NULL;  cd->open_caps = NULL;
   
Line 7950  ptr = (const pcre_uchar *)pattern + skipatstart; Line 8158  ptr = (const pcre_uchar *)pattern + skipatstart;
 code = (pcre_uchar *)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,
  &firstchar, &reqchar, NULL, cd, NULL);  &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, NULL);
 re->top_bracket = cd->bracount;  re->top_bracket = cd->bracount;
 re->top_backref = cd->top_backref;  re->top_backref = cd->top_backref;
 re->max_lookbehind = cd->max_lookbehind;  re->max_lookbehind = cd->max_lookbehind;
 re->flags = cd->external_flags | PCRE_MODE;  re->flags = cd->external_flags | PCRE_MODE;
   
if (cd->had_accept) reqchar = REQ_NONE;   /* Must disable after (*ACCEPT) */if (cd->had_accept)
   {
   reqchar = 0;              /* Must disable after (*ACCEPT) */
   reqcharflags = REQ_NONE;
   }
   
 /* If not reached end of pattern on success, there's an excess bracket. */  /* If not reached end of pattern on success, there's an excess bracket. */
   
if (errorcode == 0 && *ptr != 0) errorcode = ERR22;if (errorcode == 0 && *ptr != CHAR_NULL) errorcode = ERR22;
   
 /* Fill in the terminating state and check for disastrous overflow, but  /* Fill in the terminating state and check for disastrous overflow, but
 if debugging, leave the test till after things are printed out. */  if debugging, leave the test till after things are printed out. */
Line 7971  if debugging, leave the test till after things are pri Line 8183  if debugging, leave the test till after things are pri
 if (code - codestart > length) errorcode = ERR23;  if (code - codestart > length) errorcode = ERR23;
 #endif  #endif
   
   #ifdef SUPPORT_VALGRIND
   /* If the estimated length exceeds the really used length, mark the extra
   allocated memory as unaddressable, so that any out-of-bound reads can be
   detected. */
   VALGRIND_MAKE_MEM_NOACCESS(code, (length - (code - codestart)) * sizeof(pcre_uchar));
   #endif
   
 /* Fill in any forward references that are required. There may be repeated  /* Fill in any forward references that are required. There may be repeated
 references; optimize for them, as searching a large regex takes time. */  references; optimize for them, as searching a large regex takes time. */
   
Line 8006  if (errorcode == 0 && re->top_backref > re->top_bracke Line 8225  if (errorcode == 0 && re->top_backref > re->top_bracke
   
 /* If there were any lookbehind assertions that contained OP_RECURSE  /* If there were any lookbehind assertions that contained OP_RECURSE
 (recursions or subroutine calls), a flag is set for them to be checked here,  (recursions or subroutine calls), a flag is set for them to be checked here,
because they may contain forward references. Actual recursions can't be fixedbecause they may contain forward references. Actual recursions cannot be fixed
 length, but subroutine calls can. It is done like this so that those without  length, but subroutine calls can. It is done like this so that those without
 OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The  OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The
 exceptional ones forgo this. We scan the pattern to check that they are fixed  exceptional ones forgo this. We scan the pattern to check that they are fixed
Line 8062  if (errorcode != 0) Line 8281  if (errorcode != 0)
   }    }
   
 /* If the anchored option was not passed, set the flag if we can determine that  /* If the anchored option was not passed, set the flag if we can determine that
the pattern is anchored by virtue of ^ characters or \A or anything else (suchthe pattern is anchored by virtue of ^ characters or \A or anything else, such
as starting with .* when DOTALL is set).as starting with non-atomic .* when DOTALL is set and there are no occurrences
 of *PRUNE or *SKIP.
   
 Otherwise, if we know what the first byte has to be, save it, because that  Otherwise, if we know what the first byte has to be, save it, because that
 speeds up unanchored matches no end. If not, see if we can set the  speeds up unanchored matches no end. If not, see if we can set the
 PCRE_STARTLINE flag. This is helpful for multiline matches when all branches  PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
start with ^. and also when all branches start with .* for non-DOTALL matches.start with ^. and also when all branches start with non-atomic .* for
*/non-DOTALL matches when *PRUNE and SKIP are not present. */
   
 if ((re->options & PCRE_ANCHORED) == 0)  if ((re->options & PCRE_ANCHORED) == 0)
   {    {
  if (is_anchored(codestart, 0, cd->backref_map))  if (is_anchored(codestart, 0, cd, 0)) re->options |= PCRE_ANCHORED;
    re->options |= PCRE_ANCHORED; 
   else    else
     {      {
    if (firstchar < 0)    if (firstcharflags < 0)
      firstchar = find_firstassertedchar(codestart, FALSE);      firstchar = find_firstassertedchar(codestart, &firstcharflags, FALSE);
    if (firstchar >= 0)   /* Remove caseless flag for non-caseable chars */    if (firstcharflags >= 0)   /* Remove caseless flag for non-caseable chars */
       {        {
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
       re->first_char = firstchar & 0xff;        re->first_char = firstchar & 0xff;
#else#elif defined COMPILE_PCRE16
#ifdef COMPILE_PCRE16 
       re->first_char = firstchar & 0xffff;        re->first_char = firstchar & 0xffff;
   #elif defined COMPILE_PCRE32
         re->first_char = firstchar;
 #endif  #endif
#endif      if ((firstcharflags & REQ_CASELESS) != 0)
      if ((firstchar & REQ_CASELESS) != 0) 
         {          {
 #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)  #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
         /* We ignore non-ASCII first chars in 8 bit mode. */          /* We ignore non-ASCII first chars in 8 bit mode. */
Line 8111  if ((re->options & PCRE_ANCHORED) == 0) Line 8330  if ((re->options & PCRE_ANCHORED) == 0)
   
       re->flags |= PCRE_FIRSTSET;        re->flags |= PCRE_FIRSTSET;
       }        }
    else if (is_startline(codestart, 0, cd->backref_map))
      re->flags |= PCRE_STARTLINE;    else if (is_startline(codestart, 0, cd, 0)) re->flags |= PCRE_STARTLINE;
     }      }
   }    }
   
Line 8120  if ((re->options & PCRE_ANCHORED) == 0) Line 8339  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 (reqchar >= 0 &&if (reqcharflags >= 0 &&
     ((re->options & PCRE_ANCHORED) == 0 || (reqchar & REQ_VARY) != 0))     ((re->options & PCRE_ANCHORED) == 0 || (reqcharflags & REQ_VARY) != 0))
   {    {
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
   re->req_char = reqchar & 0xff;    re->req_char = reqchar & 0xff;
#else#elif defined COMPILE_PCRE16
#ifdef COMPILE_PCRE16 
   re->req_char = reqchar & 0xffff;    re->req_char = reqchar & 0xffff;
   #elif defined COMPILE_PCRE32
     re->req_char = reqchar;
 #endif  #endif
#endif  if ((reqcharflags & REQ_CASELESS) != 0)
  if ((reqchar & REQ_CASELESS) != 0) 
     {      {
 #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)  #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
     /* We ignore non-ASCII first chars in 8 bit mode. */      /* We ignore non-ASCII first chars in 8 bit mode. */
Line 8180  if ((re->flags & PCRE_REQCHSET) != 0) Line 8399  if ((re->flags & PCRE_REQCHSET) != 0)
     else printf("Req char = \\x%02x%s\n", ch, caseless);      else printf("Req char = \\x%02x%s\n", ch, caseless);
   }    }
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
 pcre_printint((pcre *)re, stdout, TRUE);  pcre_printint((pcre *)re, stdout, TRUE);
#else#elif defined COMPILE_PCRE16
 pcre16_printint((pcre *)re, stdout, TRUE);  pcre16_printint((pcre *)re, stdout, TRUE);
   #elif defined COMPILE_PCRE32
   pcre32_printint((pcre *)re, stdout, TRUE);
 #endif  #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
Line 8199  if (code - codestart > length) Line 8420  if (code - codestart > length)
   }    }
 #endif   /* PCRE_DEBUG */  #endif   /* PCRE_DEBUG */
   
#ifdef COMPILE_PCRE8#if defined COMPILE_PCRE8
 return (pcre *)re;  return (pcre *)re;
#else#elif defined COMPILE_PCRE16
 return (pcre16 *)re;  return (pcre16 *)re;
   #elif defined COMPILE_PCRE32
   return (pcre32 *)re;
 #endif  #endif
 }  }
   

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


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