diff options
author | ale <ale@FreeBSD.org> | 2007-03-13 07:11:54 +0000 |
---|---|---|
committer | ale <ale@FreeBSD.org> | 2007-03-13 07:11:54 +0000 |
commit | 9d853b59063f04a934165c5e9d39a63bf0c93216 (patch) | |
tree | 2372f9aeef7da050bc0b4b43840a2aa286b1c364 /devel/php5-pcre | |
parent | b099aea38548ca791d25beb2b5ccf108d5b5987c (diff) | |
download | FreeBSD-ports-9d853b59063f04a934165c5e9d39a63bf0c93216.zip FreeBSD-ports-9d853b59063f04a934165c5e9d39a63bf0c93216.tar.gz |
Update bundled pcrelib to 7.0, in sync with php4 and next php5 version.
Hopefully this will fix all the known pcre issues.
Diffstat (limited to 'devel/php5-pcre')
-rw-r--r-- | devel/php5-pcre/Makefile | 2 | ||||
-rw-r--r-- | devel/php5-pcre/files/patch-pcre-7.0 | 10262 |
2 files changed, 10263 insertions, 1 deletions
diff --git a/devel/php5-pcre/Makefile b/devel/php5-pcre/Makefile index ce9907a..5c28e9f 100644 --- a/devel/php5-pcre/Makefile +++ b/devel/php5-pcre/Makefile @@ -5,7 +5,7 @@ # $FreeBSD$ # -PORTREVISION= 4 +PORTREVISION= 5 CATEGORIES= devel diff --git a/devel/php5-pcre/files/patch-pcre-7.0 b/devel/php5-pcre/files/patch-pcre-7.0 new file mode 100644 index 0000000..724ae26 --- /dev/null +++ b/devel/php5-pcre/files/patch-pcre-7.0 @@ -0,0 +1,10262 @@ +diff -ruN ../pcre.orig/config.m4 ./config.m4 +--- ../pcre.orig/config.m4 Mon Dec 4 19:01:53 2006 ++++ ./config.m4 Fri Feb 9 22:31:18 2007 +@@ -13,7 +13,7 @@ + + if test "$PHP_PCRE_REGEX" != "no"; then + if test "$PHP_PCRE_REGEX" = "yes"; then +- PHP_NEW_EXTENSION(pcre, pcrelib/pcre_chartables.c pcrelib/pcre_ucp_searchfuncs.c pcrelib/pcre_compile.c pcrelib/pcre_config.c pcrelib/pcre_exec.c pcrelib/pcre_fullinfo.c pcrelib/pcre_get.c pcrelib/pcre_globals.c pcrelib/pcre_info.c pcrelib/pcre_maketables.c pcrelib/pcre_ord2utf8.c pcrelib/pcre_refcount.c pcrelib/pcre_study.c pcrelib/pcre_tables.c pcrelib/pcre_try_flipped.c pcrelib/pcre_valid_utf8.c pcrelib/pcre_version.c pcrelib/pcre_xclass.c php_pcre.c, $ext_shared,,-DEXPORT= -DNEWLINE=10 -DSUPPORT_UTF8 -DSUPPORT_UCP -DLINK_SIZE=2 -DPOSIX_MALLOC_THRESHOLD=10 -DMATCH_LIMIT=10000000 -DMATCH_LIMIT_RECURSION=10000000 -DMAX_NAME_SIZE=32 -DMAX_NAME_COUNT=10000 -DMAX_DUPLENGTH=30000 -I@ext_srcdir@/pcrelib) ++ PHP_NEW_EXTENSION(pcre, pcrelib/pcre_chartables.c pcrelib/pcre_ucp_searchfuncs.c pcrelib/pcre_compile.c pcrelib/pcre_config.c pcrelib/pcre_exec.c pcrelib/pcre_fullinfo.c pcrelib/pcre_get.c pcrelib/pcre_globals.c pcrelib/pcre_info.c pcrelib/pcre_maketables.c pcrelib/pcre_newline.c pcrelib/pcre_ord2utf8.c pcrelib/pcre_refcount.c pcrelib/pcre_study.c pcrelib/pcre_tables.c pcrelib/pcre_try_flipped.c pcrelib/pcre_valid_utf8.c pcrelib/pcre_version.c pcrelib/pcre_xclass.c php_pcre.c, $ext_shared,,-DEXPORT= -DNEWLINE=10 -DSUPPORT_UTF8 -DSUPPORT_UCP -DLINK_SIZE=2 -DPOSIX_MALLOC_THRESHOLD=10 -DMATCH_LIMIT=10000000 -DMATCH_LIMIT_RECURSION=10000000 -DMAX_NAME_SIZE=32 -DMAX_NAME_COUNT=10000 -DMAX_DUPLENGTH=30000 -DEBCDIC=0 -I@ext_srcdir@/pcrelib) + PHP_ADD_BUILD_DIR($ext_builddir/pcrelib) + PHP_INSTALL_HEADERS([ext/pcre], [php_pcre.h pcrelib/]) + AC_DEFINE(HAVE_BUNDLED_PCRE, 1, [ ]) +diff -ruN ../pcre.orig/pcrelib/dftables.c ./pcrelib/dftables.c +--- ../pcre.orig/pcrelib/dftables.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/dftables.c Fri Feb 9 22:31:19 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -86,7 +86,16 @@ + fprintf(f, + "This file contains the default tables for characters with codes less than\n" + "128 (ASCII characters). These tables are used when no external tables are\n" +- "passed to PCRE. */\n\n" ++ "passed to PCRE.\n\n"); ++fprintf(f, ++ "The following #include is present because without it gcc 4.x may remove\n" ++ "the array definition from the final binary if PCRE is built into a static\n" ++ "library and dead code stripping is activated. This leads to link errors.\n" ++ "Pulling in the header ensures that the array gets flagged as \"someone\n" ++ "outside this compilation unit might reference this\" and so it will always\n" ++ "be supplied to the linker. */\n\n" ++ "#include \"pcre_internal.h\"\n\n"); ++fprintf(f, + "const unsigned char _pcre_default_tables[] = {\n\n" + "/* This table is a lower casing table. */\n\n"); + +diff -ruN ../pcre.orig/pcrelib/pcre.h ./pcrelib/pcre.h +--- ../pcre.orig/pcrelib/pcre.h Wed Jan 3 19:32:27 2007 ++++ ./pcrelib/pcre.h Fri Feb 9 22:31:19 2007 +@@ -5,7 +5,7 @@ + /* This is the public header file for the PCRE library, to be #included by + applications that call the PCRE functions. + +- Copyright (c) 1997-2005 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -38,7 +38,7 @@ + + #ifndef _PCRE_H + #define _PCRE_H +- ++ + #include "php_compat.h" + + /* The current PCRE version information. */ +@@ -54,10 +54,10 @@ + cannot run ./configure. As it now stands, this file need not be edited in that + circumstance. */ + +-#define PCRE_MAJOR 6 +-#define PCRE_MINOR 7 ++#define PCRE_MAJOR 7 ++#define PCRE_MINOR 0 + #define PCRE_PRERELEASE +-#define PCRE_DATE 04-Jul-2006 ++#define PCRE_DATE 18-Dec-2006 + + /* Win32 uses DLL by default; it needs special stuff for exported functions + when building PCRE. */ +@@ -120,6 +120,7 @@ + #define PCRE_NEWLINE_CR 0x00100000 + #define PCRE_NEWLINE_LF 0x00200000 + #define PCRE_NEWLINE_CRLF 0x00300000 ++#define PCRE_NEWLINE_ANY 0x00400000 + + /* Exec-time and get/set-time error codes */ + +@@ -127,7 +128,8 @@ + #define PCRE_ERROR_NULL (-2) + #define PCRE_ERROR_BADOPTION (-3) + #define PCRE_ERROR_BADMAGIC (-4) +-#define PCRE_ERROR_UNKNOWN_NODE (-5) ++#define PCRE_ERROR_UNKNOWN_OPCODE (-5) ++#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ + #define PCRE_ERROR_NOMEMORY (-6) + #define PCRE_ERROR_NOSUBSTRING (-7) + #define PCRE_ERROR_MATCHLIMIT (-8) +@@ -144,6 +146,8 @@ + #define PCRE_ERROR_DFA_WSSIZE (-19) + #define PCRE_ERROR_DFA_RECURSE (-20) + #define PCRE_ERROR_RECURSIONLIMIT (-21) ++#define PCRE_ERROR_NULLWSLIMIT (-22) ++#define PCRE_ERROR_BADNEWLINE (-23) + + /* Request types for pcre_fullinfo() */ + +diff -ruN ../pcre.orig/pcrelib/pcre_compile.c ./pcrelib/pcre_compile.c +--- ../pcre.orig/pcrelib/pcre_compile.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_compile.c Fri Feb 9 22:31:19 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -42,7 +42,11 @@ + supporting internal functions that are not used by other modules. */ + + +-#define NLBLOCK cd /* The block containing newline information */ ++#define NLBLOCK cd /* Block containing newline information */ ++#define PSSTART start_pattern /* Field containing processed string start */ ++#define PSEND end_pattern /* Field containing processed string end */ ++ ++ + #include "pcre_internal.h" + + +@@ -54,18 +58,23 @@ + #endif + + +- + /************************************************* + * Code parameters and static tables * + *************************************************/ + +-/* Maximum number of items on the nested bracket stacks at compile time. This +-applies to the nesting of all kinds of parentheses. It does not limit +-un-nested, non-capturing parentheses. This number can be made bigger if +-necessary - it is used to dimension one int and one unsigned char vector at +-compile time. */ ++/* This value specifies the size of stack workspace that is used during the ++first pre-compile phase that determines how much memory is required. The regex ++is partly compiled into this space, but the compiled parts are discarded as ++soon as they can be, so that hopefully there will never be an overrun. The code ++does, however, check for an overrun. The largest amount I've seen used is 218, ++so this number is very generous. ++ ++The same workspace is used during the second, actual compile phase for ++remembering forward references to groups so that they can be filled in at the ++end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE ++is 4 there is plenty of room. */ + +-#define BRASTACK_SIZE 200 ++#define COMPILE_WORK_SIZE (4096) + + + /* Table for handling escaped characters in the range '0'-'z'. Positive returns +@@ -79,10 +88,10 @@ + 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ + '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, /* @ - G */ + 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ +--ESC_P, -ESC_Q, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ ++-ESC_P, -ESC_Q, -ESC_R, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ + -ESC_X, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ + '`', 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* ` - g */ +- 0, 0, 0, 0, 0, 0, ESC_n, 0, /* h - o */ ++ 0, 0, 0, -ESC_k, 0, 0, ESC_n, 0, /* h - o */ + -ESC_p, 0, ESC_r, -ESC_s, ESC_tee, 0, 0, -ESC_w, /* p - w */ + 0, 0, -ESC_z /* x - z */ + }; +@@ -98,7 +107,7 @@ + /* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', + /* 80 */ 0, 7, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, + /* 88 */ 0, 0, 0, '{', 0, 0, 0, 0, +-/* 90 */ 0, 0, 0, 'l', 0, ESC_n, 0, -ESC_p, ++/* 90 */ 0, 0, -ESC_k, 'l', 0, ESC_n, 0, -ESC_p, + /* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, + /* A0 */ 0, '~', -ESC_s, ESC_tee, 0, 0, -ESC_w, 0, + /* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, +@@ -107,7 +116,7 @@ + /* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, + /* C8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* D0 */ '}', 0, 0, 0, 0, 0, 0, -ESC_P, +-/* D8 */-ESC_Q, 0, 0, 0, 0, 0, 0, 0, ++/* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, + /* E0 */ '\\', 0, -ESC_S, 0, 0, 0, -ESC_W, -ESC_X, + /* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, + /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, +@@ -156,8 +165,13 @@ + }; + + ++#define STRING(a) # a ++#define XSTRING(s) STRING(s) ++ + /* The texts of compile-time error messages. These are "char *" because they +-are passed to the outside world. */ ++are passed to the outside world. Do not ever re-use any error number, because ++they are documented. Always add a new error instead. Messages marked DEAD below ++are no longer used. */ + + static const char *error_texts[] = { + "no error", +@@ -172,7 +186,7 @@ + "range out of order in character class", + "nothing to repeat", + /* 10 */ +- "operand of unlimited repeat could match the empty string", ++ "operand of unlimited repeat could match the empty string", /** DEAD **/ + "internal error: unexpected repeat", + "unrecognized character after (?", + "POSIX named classes are supported only within a class", +@@ -182,7 +196,7 @@ + "erroffset passed as NULL", + "unknown option bit(s) set", + "missing ) after comment", +- "parentheses nested too deeply", ++ "parentheses nested too deeply", /** DEAD **/ + /* 20 */ + "regular expression too large", + "failed to get memory", +@@ -199,7 +213,7 @@ + "unknown POSIX class name", + "POSIX collating elements are not supported", + "this version of PCRE is not compiled with PCRE_UTF8 support", +- "spare error", ++ "spare error", /** DEAD **/ + "character value in \\x{...} sequence is too large", + /* 35 */ + "invalid condition (?(0)", +@@ -210,18 +224,25 @@ + /* 40 */ + "recursive call could loop indefinitely", + "unrecognized character after (?P", +- "syntax error after (?P", ++ "syntax error in subpattern name (missing terminator)", + "two named subpatterns have the same name", + "invalid UTF-8 string", + /* 45 */ + "support for \\P, \\p, and \\X has not been compiled", + "malformed \\P or \\p sequence", + "unknown property name after \\P or \\p", +- "subpattern name is too long (maximum 32 characters)", +- "too many named subpatterns (maximum 10,000)", ++ "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)", ++ "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")", + /* 50 */ + "repeated subpattern is too long", +- "octal value is greater than \\377 (not in UTF-8 mode)" ++ "octal value is greater than \\377 (not in UTF-8 mode)", ++ "internal error: overran compiling workspace", ++ "internal error: previously-checked referenced subpattern not found", ++ "DEFINE group contains more than one branch", ++ /* 55 */ ++ "repeating a DEFINE group is not allowed", ++ "inconsistent NEWLINE options", ++ "\\g is not followed by an (optionally braced) non-zero number" + }; + + +@@ -352,8 +373,8 @@ + /* Definition to allow mutual recursion */ + + static BOOL +- compile_regex(int, int, int *, uschar **, const uschar **, int *, BOOL, int, +- int *, int *, branch_chain *, compile_data *); ++ compile_regex(int, int, uschar **, const uschar **, int *, BOOL, int, int *, ++ int *, branch_chain *, compile_data *, int *); + + + +@@ -363,9 +384,11 @@ + + /* 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 which +-encodes one of the more complicated things such as \d. When UTF-8 is enabled, +-a positive value greater than 255 may be returned. On entry, ptr is pointing at +-the \. On exit, it is on the final character of the escape sequence. ++encodes one of the more complicated things such as \d. A backreference to group ++n is returned as -(ESC_REF + n); ESC_REF is the highest ESC_xxx macro. When ++UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, ++ptr is pointing at the \. On exit, it is on the final character of the escape ++sequence. + + Arguments: + ptrptr points to the pattern position pointer +@@ -412,6 +435,8 @@ + else + { + const uschar *oldptr; ++ BOOL braced, negated; ++ + switch (c) + { + /* A number of Perl escapes are not handled by PCRE. We give an explicit +@@ -425,6 +450,48 @@ + *errorcodeptr = ERR37; + break; + ++ /* \g must be followed by a number, either plain or braced. If positive, it ++ is an absolute backreference. If negative, it is a relative backreference. ++ This is a Perl 5.10 feature. */ ++ ++ case 'g': ++ if (ptr[1] == '{') ++ { ++ braced = TRUE; ++ ptr++; ++ } ++ else braced = FALSE; ++ ++ if (ptr[1] == '-') ++ { ++ negated = TRUE; ++ ptr++; ++ } ++ else negated = FALSE; ++ ++ c = 0; ++ while ((digitab[ptr[1]] & ctype_digit) != 0) ++ c = c * 10 + *(++ptr) - '0'; ++ ++ if (c == 0 || (braced && *(++ptr) != '}')) ++ { ++ *errorcodeptr = ERR57; ++ return 0; ++ } ++ ++ if (negated) ++ { ++ if (c > bracount) ++ { ++ *errorcodeptr = ERR15; ++ return 0; ++ } ++ c = bracount - (c - 1); ++ } ++ ++ c = -(ESC_REF + c); ++ break; ++ + /* The handling of escape sequences consisting of a string of digits + starting with one that is not zero is not straightforward. By experiment, + the way Perl works seems to be as follows: +@@ -532,7 +599,9 @@ + } + break; + +- /* Other special escapes not starting with a digit are straightforward */ ++ /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped. ++ This coding is ASCII-specific, but then the whole concept of \cx is ++ ASCII-specific. (However, an EBCDIC equivalent has now been added.) */ + + case 'c': + c = *(++ptr); +@@ -542,10 +611,6 @@ + return 0; + } + +- /* A letter is upper-cased; then the 0x40 bit is flipped. This coding +- is ASCII-specific, but then the whole concept of \cx is ASCII-specific. +- (However, an EBCDIC equivalent has now been added.) */ +- + #if !EBCDIC /* ASCII coding */ + if (c >= 'a' && c <= 'z') c -= 32; + c ^= 0x40; +@@ -772,42 +837,111 @@ + + + /************************************************* +-* Find forward referenced named subpattern * ++* Find forward referenced subpattern * + *************************************************/ + +-/* This function scans along a pattern looking for capturing subpatterns, and +-counting them. If it finds a named pattern that matches the name it is given, +-it returns its number. This is used for forward references to named +-subpatterns. We know that if (?P< is encountered, the name will be terminated +-by '>' because that is checked in the first pass. ++/* This function scans along a pattern's text looking for capturing ++subpatterns, and counting them. If it finds a named pattern that matches the ++name it is given, it returns its number. Alternatively, if the name is NULL, it ++returns when it reaches a given numbered subpattern. This is used for forward ++references to subpatterns. We know that if (?P< is encountered, the name will ++be terminated by '>' because that is checked in the first pass. + + Arguments: +- pointer current position in the pattern +- count current count of capturing parens +- name name to seek +- namelen name length ++ ptr current position in the pattern ++ count current count of capturing parens so far encountered ++ name name to seek, or NULL if seeking a numbered subpattern ++ lorn name length, or subpattern number if name is NULL ++ xmode TRUE if we are in /x mode + + Returns: the number of the named subpattern, or -1 if not found + */ + + static int +-find_named_parens(const uschar *ptr, int count, const uschar *name, int namelen) ++find_parens(const uschar *ptr, int count, const uschar *name, int lorn, ++ BOOL xmode) + { + const uschar *thisname; ++ + for (; *ptr != 0; ptr++) + { +- if (*ptr == '\\' && ptr[1] != 0) { ptr++; continue; } ++ int term; ++ ++ /* Skip over backslashed characters and also entire \Q...\E */ ++ ++ if (*ptr == '\\') ++ { ++ if (*(++ptr) == 0) return -1; ++ if (*ptr == 'Q') for (;;) ++ { ++ while (*(++ptr) != 0 && *ptr != '\\'); ++ if (*ptr == 0) return -1; ++ if (*(++ptr) == 'E') break; ++ } ++ continue; ++ } ++ ++ /* Skip over character classes */ ++ ++ if (*ptr == '[') ++ { ++ while (*(++ptr) != ']') ++ { ++ if (*ptr == '\\') ++ { ++ if (*(++ptr) == 0) return -1; ++ if (*ptr == 'Q') for (;;) ++ { ++ while (*(++ptr) != 0 && *ptr != '\\'); ++ if (*ptr == 0) return -1; ++ if (*(++ptr) == 'E') break; ++ } ++ continue; ++ } ++ } ++ continue; ++ } ++ ++ /* Skip comments in /x mode */ ++ ++ if (xmode && *ptr == '#') ++ { ++ while (*(++ptr) != 0 && *ptr != '\n'); ++ if (*ptr == 0) return -1; ++ continue; ++ } ++ ++ /* An opening parens must now be a real metacharacter */ ++ + if (*ptr != '(') continue; +- if (ptr[1] != '?') { count++; continue; } +- if (ptr[2] == '(') { ptr += 2; continue; } +- if (ptr[2] != 'P' || ptr[3] != '<') continue; ++ if (ptr[1] != '?') ++ { ++ count++; ++ if (name == NULL && count == lorn) return count; ++ continue; ++ } ++ ++ ptr += 2; ++ if (*ptr == 'P') ptr++; /* Allow optional P */ ++ ++ /* We have to disambiguate (?<! and (?<= from (?<name> */ ++ ++ if ((*ptr != '<' || ptr[1] == '!' || ptr[1] == '=') && ++ *ptr != '\'') ++ continue; ++ + count++; +- ptr += 4; ++ ++ if (name == NULL && count == lorn) return count; ++ term = *ptr++; ++ if (term == '<') term = '>'; + thisname = ptr; +- while (*ptr != '>') ptr++; +- if (namelen == ptr - thisname && strncmp(name, thisname, namelen) == 0) ++ while (*ptr != term) ptr++; ++ if (name != NULL && lorn == ptr - thisname && ++ strncmp((const char *)name, (const char *)thisname, lorn) == 0) + return count; + } ++ + return -1; + } + +@@ -862,7 +996,8 @@ + + case OP_CALLOUT: + case OP_CREF: +- case OP_BRANUMBER: ++ case OP_RREF: ++ case OP_DEF: + code += _pcre_OP_lengths[*code]; + break; + +@@ -907,14 +1042,14 @@ + { + int d; + register int op = *cc; +- if (op >= OP_BRA) op = OP_BRA; + + switch (op) + { ++ case OP_CBRA: + case OP_BRA: + case OP_ONCE: + case OP_COND: +- d = find_fixedlength(cc, options); ++ d = find_fixedlength(cc + ((op == OP_CBRA)? 2:0), options); + if (d < 0) return d; + branchlength += d; + do cc += GET(cc, 1); while (*cc == OP_ALT); +@@ -949,8 +1084,9 @@ + /* Skip over things that don't match chars */ + + case OP_REVERSE: +- case OP_BRANUMBER: + case OP_CREF: ++ case OP_RREF: ++ case OP_DEF: + case OP_OPT: + case OP_CALLOUT: + case OP_SOD: +@@ -1094,21 +1230,18 @@ + + if (c == OP_XCLASS) code += GET(code, 1); + +- /* Handle bracketed group */ ++ /* Handle capturing bracket */ + +- else if (c > OP_BRA) ++ else if (c == OP_CBRA) + { +- int n = c - OP_BRA; +- if (n > EXTRACT_BASIC_MAX) n = GET2(code, 2+LINK_SIZE); ++ int n = GET2(code, 1+LINK_SIZE); + if (n == number) return (uschar *)code; +- code += _pcre_OP_lengths[OP_BRA]; ++ code += _pcre_OP_lengths[c]; + } + +- /* Otherwise, we get the item's length from the table. In UTF-8 mode, opcodes +- that are followed by a character may be followed by a multi-byte character. +- The length in the table is a minimum, so we have to scan along to skip the +- extra bytes. All opcodes are less than 128, so we can use relatively +- efficient code. */ ++ /* In UTF-8 mode, opcodes that are followed by a character may be followed by ++ a multi-byte character. The length in the table is a minimum, so we have to ++ arrange to skip the extra bytes. */ + + else + { +@@ -1120,13 +1253,17 @@ + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: ++ case OP_POSUPTO: + case OP_STAR: + case OP_MINSTAR: ++ case OP_POSSTAR: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + case OP_QUERY: + case OP_MINQUERY: +- while ((*code & 0xc0) == 0x80) code++; ++ case OP_POSQUERY: ++ if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; + break; + } + } +@@ -1164,18 +1301,10 @@ + + if (c == OP_XCLASS) code += GET(code, 1); + +- /* All bracketed groups have the same length. */ +- +- else if (c > OP_BRA) +- { +- code += _pcre_OP_lengths[OP_BRA]; +- } +- + /* Otherwise, we get the item's length from the table. In UTF-8 mode, opcodes + that are followed by a character may be followed by a multi-byte character. +- The length in the table is a minimum, so we have to scan along to skip the +- extra bytes. All opcodes are less than 128, so we can use relatively +- efficient code. */ ++ The length in the table is a minimum, so we have to arrange to skip the extra ++ bytes. */ + + else + { +@@ -1187,13 +1316,17 @@ + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: ++ case OP_POSUPTO: + case OP_STAR: + case OP_MINSTAR: ++ case OP_POSSTAR: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + case OP_QUERY: + case OP_MINQUERY: +- while ((*code & 0xc0) == 0x80) code++; ++ case OP_POSQUERY: ++ if (code[-1] >= 0xc0) code += _pcre_utf8_table4[code[-1] & 0x3f]; + break; + } + } +@@ -1207,10 +1340,11 @@ + *************************************************/ + + /* This function scans through a branch of a compiled pattern to see whether it +-can match the empty string or not. It is called only from could_be_empty() +-below. Note that first_significant_code() skips over assertions. If we hit an +-unclosed bracket, we return "empty" - this means we've struck an inner bracket +-whose current branch will already have been scanned. ++can match the empty string or not. It is called from could_be_empty() ++below and from compile_branch() when checking for an unlimited repeat of a ++group that can match nothing. Note that first_significant_code() skips over ++assertions. If we hit an unclosed bracket, we return "empty" - this means we've ++struck an inner bracket whose current branch will already have been scanned. + + Arguments: + code points to start of search +@@ -1224,7 +1358,7 @@ + could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8) + { + register int c; +-for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0, TRUE); ++for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE); + code < endcode; + code = first_significant_code(code + _pcre_OP_lengths[c], NULL, 0, TRUE)) + { +@@ -1232,7 +1366,7 @@ + + c = *code; + +- if (c >= OP_BRA) ++ if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE) + { + BOOL empty_branch; + if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ +@@ -1248,11 +1382,18 @@ + } + while (*code == OP_ALT); + if (!empty_branch) return FALSE; /* All branches are non-empty */ +- code += 1 + LINK_SIZE; +- c = *code; ++ ++ /* Move past the KET and fudge things so that the increment in the "for" ++ above has no effect. */ ++ ++ c = OP_END; ++ code += 1 + LINK_SIZE - _pcre_OP_lengths[c]; ++ continue; + } + +- else switch (c) ++ /* Handle the other opcodes */ ++ ++ switch (c) + { + /* Check for quantifiers after a class */ + +@@ -1308,12 +1449,15 @@ + case OP_NOT: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + case OP_EXACT: + case OP_NOTPLUS: + case OP_NOTMINPLUS: ++ case OP_NOTPOSPLUS: + case OP_NOTEXACT: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: ++ case OP_TYPEPOSPLUS: + case OP_TYPEEXACT: + return FALSE; + +@@ -1325,16 +1469,19 @@ + case OP_ALT: + return TRUE; + +- /* In UTF-8 mode, STAR, MINSTAR, QUERY, MINQUERY, UPTO, and MINUPTO may be +- followed by a multibyte character */ ++ /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO, ++ MINUPTO, and POSUPTO may be followed by a multibyte character */ + + #ifdef SUPPORT_UTF8 + case OP_STAR: + case OP_MINSTAR: ++ case OP_POSSTAR: + case OP_QUERY: + case OP_MINQUERY: ++ case OP_POSQUERY: + case OP_UPTO: + case OP_MINUPTO: ++ case OP_POSUPTO: + if (utf8) while ((code[2] & 0xc0) == 0x80) code++; + break; + #endif +@@ -1452,26 +1599,57 @@ + optional (i.e. the minimum quantifier is zero), OP_BRAZERO is inserted before + it, after it has been compiled. This means that any OP_RECURSE items within it + that refer to the group itself or any contained groups have to have their +-offsets adjusted. That is the job of this function. Before it is called, the +-partially compiled regex must be temporarily terminated with OP_END. ++offsets adjusted. That one of the jobs of this function. Before it is called, ++the partially compiled regex must be temporarily terminated with OP_END. ++ ++This function has been extended with the possibility of forward references for ++recursions and subroutine calls. It must also check the list of such references ++for the group we are dealing with. If it finds that one of the recursions in ++the current group is on this list, it adjusts the offset in the list, not the ++value in the reference (which is a group number). + + Arguments: + group points to the start of the group + adjust the amount by which the group is to be moved + utf8 TRUE in UTF-8 mode + cd contains pointers to tables etc. ++ save_hwm the hwm forward reference pointer at the start of the group + + Returns: nothing + */ + + static void +-adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd) ++adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd, ++ uschar *save_hwm) + { + uschar *ptr = group; + while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL) + { +- int offset = GET(ptr, 1); +- if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); ++ int offset; ++ uschar *hc; ++ ++ /* See if this recursion is on the forward reference list. If so, adjust the ++ reference. */ ++ ++ for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE) ++ { ++ offset = GET(hc, 0); ++ if (cd->start_code + offset == ptr + 1) ++ { ++ PUT(hc, 0, offset + adjust); ++ break; ++ } ++ } ++ ++ /* Otherwise, adjust the recursion offset if it's after the start of this ++ group. */ ++ ++ if (hc >= cd->hwm) ++ { ++ offset = GET(ptr, 1); ++ if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); ++ } ++ + ptr += 1 + LINK_SIZE; + } + } +@@ -1550,12 +1728,13 @@ + */ + + static BOOL +-get_othercase_range(int *cptr, int d, int *ocptr, int *odptr) ++get_othercase_range(unsigned int *cptr, unsigned int d, unsigned int *ocptr, ++ unsigned int *odptr) + { +-int c, othercase, next; ++unsigned int c, othercase, next; + + for (c = *cptr; c <= d; c++) +- { if ((othercase = _pcre_ucp_othercase(c)) >= 0) break; } ++ { if ((othercase = _pcre_ucp_othercase(c)) != NOTACHAR) break; } + + if (c > d) return FALSE; + +@@ -1576,17 +1755,249 @@ + #endif /* SUPPORT_UCP */ + + ++ ++/************************************************* ++* Check if auto-possessifying is possible * ++*************************************************/ ++ ++/* This function is called for unlimited repeats of certain items, to see ++whether the next thing could possibly match the repeated item. If not, it makes ++sense to automatically possessify the repeated item. ++ ++Arguments: ++ op_code the repeated op code ++ this data for this item, depends on the opcode ++ utf8 TRUE in UTF-8 mode ++ utf8_char used for utf8 character bytes, NULL if not relevant ++ ptr next character in pattern ++ options options bits ++ cd contains pointers to tables etc. ++ ++Returns: TRUE if possessifying is wanted ++*/ ++ ++static BOOL ++check_auto_possessive(int op_code, int item, BOOL utf8, uschar *utf8_char, ++ const uschar *ptr, int options, compile_data *cd) ++{ ++int next; ++ ++/* Skip whitespace and comments in extended mode */ ++ ++if ((options & PCRE_EXTENDED) != 0) ++ { ++ for (;;) ++ { ++ while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; ++ if (*ptr == '#') ++ { ++ while (*(++ptr) != 0) ++ if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } ++ } ++ else break; ++ } ++ } ++ ++/* If the next item is one that we can handle, get its value. A non-negative ++value is a character, a negative value is an escape value. */ ++ ++if (*ptr == '\\') ++ { ++ int temperrorcode = 0; ++ next = check_escape(&ptr, &temperrorcode, cd->bracount, options, FALSE); ++ if (temperrorcode != 0) return FALSE; ++ ptr++; /* Point after the escape sequence */ ++ } ++ ++else if ((cd->ctypes[*ptr] & ctype_meta) == 0) ++ { ++#ifdef SUPPORT_UTF8 ++ if (utf8) { GETCHARINC(next, ptr); } else ++#endif ++ next = *ptr++; ++ } ++ ++else return FALSE; ++ ++/* Skip whitespace and comments in extended mode */ ++ ++if ((options & PCRE_EXTENDED) != 0) ++ { ++ for (;;) ++ { ++ while ((cd->ctypes[*ptr] & ctype_space) != 0) ptr++; ++ if (*ptr == '#') ++ { ++ while (*(++ptr) != 0) ++ if (IS_NEWLINE(ptr)) { ptr += cd->nllen; break; } ++ } ++ else break; ++ } ++ } ++ ++/* If the next thing is itself optional, we have to give up. */ ++ ++if (*ptr == '*' || *ptr == '?' || strncmp((char *)ptr, "{0,", 3) == 0) ++ return FALSE; ++ ++/* Now compare the next item with the previous opcode. If the previous is a ++positive single character match, "item" either contains the character or, if ++"item" is greater than 127 in utf8 mode, the character's bytes are in ++utf8_char. */ ++ ++ ++/* Handle cases when the next item is a character. */ ++ ++if (next >= 0) switch(op_code) ++ { ++ case OP_CHAR: ++#ifdef SUPPORT_UTF8 ++ if (utf8 && item > 127) { GETCHAR(item, utf8_char); } ++#endif ++ return item != next; ++ ++ /* For CHARNC (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. */ ++ ++ case OP_CHARNC: ++#ifdef SUPPORT_UTF8 ++ if (utf8 && item > 127) { GETCHAR(item, utf8_char); } ++#endif ++ if (item == next) return FALSE; ++#ifdef SUPPORT_UTF8 ++ if (utf8) ++ { ++ unsigned int othercase; ++ if (next < 128) othercase = cd->fcc[next]; else ++#ifdef SUPPORT_UCP ++ othercase = _pcre_ucp_othercase((unsigned int)next); ++#else ++ othercase = NOTACHAR; ++#endif ++ return (unsigned int)item != othercase; ++ } ++ else ++#endif /* SUPPORT_UTF8 */ ++ return (item != cd->fcc[next]); /* Non-UTF-8 mode */ ++ ++ /* For OP_NOT, "item" must be a single-byte character. */ ++ ++ case OP_NOT: ++ if (next < 0) return FALSE; /* Not a character */ ++ if (item == next) return TRUE; ++ if ((options & PCRE_CASELESS) == 0) return FALSE; ++#ifdef SUPPORT_UTF8 ++ if (utf8) ++ { ++ unsigned int othercase; ++ if (next < 128) othercase = cd->fcc[next]; else ++#ifdef SUPPORT_UCP ++ othercase = _pcre_ucp_othercase(next); ++#else ++ othercase = NOTACHAR; ++#endif ++ return (unsigned int)item == othercase; ++ } ++ else ++#endif /* SUPPORT_UTF8 */ ++ return (item == cd->fcc[next]); /* Non-UTF-8 mode */ ++ ++ case OP_DIGIT: ++ return next > 127 || (cd->ctypes[next] & ctype_digit) == 0; ++ ++ case OP_NOT_DIGIT: ++ return next <= 127 && (cd->ctypes[next] & ctype_digit) != 0; ++ ++ case OP_WHITESPACE: ++ return next > 127 || (cd->ctypes[next] & ctype_space) == 0; ++ ++ case OP_NOT_WHITESPACE: ++ return next <= 127 && (cd->ctypes[next] & ctype_space) != 0; ++ ++ case OP_WORDCHAR: ++ return next > 127 || (cd->ctypes[next] & ctype_word) == 0; ++ ++ case OP_NOT_WORDCHAR: ++ return next <= 127 && (cd->ctypes[next] & ctype_word) != 0; ++ ++ default: ++ return FALSE; ++ } ++ ++ ++/* Handle the case when the next item is \d, \s, etc. */ ++ ++switch(op_code) ++ { ++ case OP_CHAR: ++ case OP_CHARNC: ++#ifdef SUPPORT_UTF8 ++ if (utf8 && item > 127) { GETCHAR(item, utf8_char); } ++#endif ++ switch(-next) ++ { ++ case ESC_d: ++ return item > 127 || (cd->ctypes[item] & ctype_digit) == 0; ++ ++ case ESC_D: ++ return item <= 127 && (cd->ctypes[item] & ctype_digit) != 0; ++ ++ case ESC_s: ++ return item > 127 || (cd->ctypes[item] & ctype_space) == 0; ++ ++ case ESC_S: ++ return item <= 127 && (cd->ctypes[item] & ctype_space) != 0; ++ ++ case ESC_w: ++ return item > 127 || (cd->ctypes[item] & ctype_word) == 0; ++ ++ case ESC_W: ++ return item <= 127 && (cd->ctypes[item] & ctype_word) != 0; ++ ++ default: ++ return FALSE; ++ } ++ ++ case OP_DIGIT: ++ return next == -ESC_D || next == -ESC_s || next == -ESC_W; ++ ++ case OP_NOT_DIGIT: ++ return next == -ESC_d; ++ ++ case OP_WHITESPACE: ++ return next == -ESC_S || next == -ESC_d || next == -ESC_w; ++ ++ case OP_NOT_WHITESPACE: ++ return next == -ESC_s; ++ ++ case OP_WORDCHAR: ++ return next == -ESC_W || next == -ESC_s; ++ ++ case OP_NOT_WORDCHAR: ++ return next == -ESC_w || next == -ESC_d; ++ ++ default: ++ return FALSE; ++ } ++ ++/* Control does not reach here */ ++} ++ ++ ++ + /************************************************* + * Compile one branch * + *************************************************/ + +-/* Scan the pattern, compiling it into the code vector. If the options are ++/* Scan the pattern, compiling it into the a vector. If the options are + changed during the branch, the pointer is used to change the external options +-bits. ++bits. This function is used during the pre-compile phase when we are trying ++to find out the amount of memory needed, as well as during the real compile ++phase. The value of lengthptr distinguishes the two phases. + + Arguments: + optionsptr pointer to the option bits +- brackets points to number of extracting brackets used + codeptr points to the pointer to the current code point + ptrptr points to the current pattern pointer + errorcodeptr points to error code variable +@@ -1594,15 +2005,17 @@ + reqbyteptr set to the last literal character required, else < 0 + bcptr points to current branch chain + cd contains pointers to tables etc. ++ lengthptr NULL during the real compile phase ++ points to length accumulator during pre-compile phase + + Returns: TRUE on success + FALSE, with *errorcodeptr set non-zero on error + */ + + static BOOL +-compile_branch(int *optionsptr, int *brackets, uschar **codeptr, +- const uschar **ptrptr, int *errorcodeptr, int *firstbyteptr, +- int *reqbyteptr, branch_chain *bcptr, compile_data *cd) ++compile_branch(int *optionsptr, uschar **codeptr, const uschar **ptrptr, ++ int *errorcodeptr, int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, ++ compile_data *cd, int *lengthptr) + { + int repeat_type, op_type; + int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ +@@ -1613,8 +2026,11 @@ + int req_caseopt, reqvary, tempreqvary; + int options = *optionsptr; + int after_manual_callout = 0; ++int length_prevgroup = 0; + register int c; + register uschar *code = *codeptr; ++uschar *last_code = code; ++uschar *orig_code = code; + uschar *tempcode; + BOOL inescq = FALSE; + BOOL groupsetfirstbyte = FALSE; +@@ -1622,6 +2038,7 @@ + const uschar *tempptr; + uschar *previous = NULL; + uschar *previous_callout = NULL; ++uschar *save_hwm = NULL; + uschar classbits[32]; + + #ifdef SUPPORT_UTF8 +@@ -1631,6 +2048,11 @@ + uschar utf8_char[6]; + #else + BOOL utf8 = FALSE; ++uschar *utf8_char = NULL; ++#endif ++ ++#ifdef DEBUG ++if (lengthptr != NULL) DPRINTF((">> start branch\n")); + #endif + + /* Set up the default and non-default settings for greediness */ +@@ -1664,6 +2086,7 @@ + BOOL negate_class; + BOOL possessive_quantifier; + BOOL is_quantifier; ++ BOOL is_recurse; + int class_charcount; + int class_lastchar; + int newoptions; +@@ -1671,13 +2094,68 @@ + int skipbytes; + int subreqbyte; + int subfirstbyte; ++ int terminator; + int mclength; + uschar mcbuffer[8]; + +- /* Next byte in the pattern */ ++ /* Get next byte in the pattern */ + + c = *ptr; + ++ /* If we are in the pre-compile phase, accumulate the length used for the ++ previous cycle of this loop. */ ++ ++ if (lengthptr != NULL) ++ { ++#ifdef DEBUG ++ if (code > cd->hwm) cd->hwm = code; /* High water info */ ++#endif ++ if (code > cd->start_workspace + COMPILE_WORK_SIZE) /* Check for overrun */ ++ { ++ *errorcodeptr = ERR52; ++ goto FAILED; ++ } ++ ++ /* There is at least one situation where code goes backwards: this is the ++ case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, ++ the class is simply eliminated. However, it is created first, so we have to ++ allow memory for it. Therefore, don't ever reduce the length at this point. ++ */ ++ ++ if (code < last_code) code = last_code; ++ *lengthptr += code - last_code; ++ DPRINTF(("length=%d added %d c=%c\n", *lengthptr, code - last_code, c)); ++ ++ /* If "previous" is set and it is not at the start of the work space, move ++ it back to there, in order to avoid filling up the work space. Otherwise, ++ if "previous" is NULL, reset the current code pointer to the start. */ ++ ++ if (previous != NULL) ++ { ++ if (previous > orig_code) ++ { ++ memmove(orig_code, previous, code - previous); ++ code -= previous - orig_code; ++ previous = orig_code; ++ } ++ } ++ else code = orig_code; ++ ++ /* Remember where this code item starts so we can pick up the length ++ next time round. */ ++ ++ last_code = code; ++ } ++ ++ /* In the real compile phase, just check the workspace used by the forward ++ reference list. */ ++ ++ else if (cd->hwm > cd->start_workspace + COMPILE_WORK_SIZE) ++ { ++ *errorcodeptr = ERR52; ++ goto FAILED; ++ } ++ + /* If in \Q...\E, check for the end; if not, we have a literal */ + + if (inescq && c != 0) +@@ -1692,7 +2170,8 @@ + { + if (previous_callout != NULL) + { +- complete_callout(previous_callout, ptr, cd); ++ if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ ++ complete_callout(previous_callout, ptr, cd); + previous_callout = NULL; + } + if ((options & PCRE_AUTO_CALLOUT) != 0) +@@ -1713,7 +2192,8 @@ + if (!is_quantifier && previous_callout != NULL && + after_manual_callout-- <= 0) + { +- complete_callout(previous_callout, ptr, cd); ++ if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ ++ complete_callout(previous_callout, ptr, cd); + previous_callout = NULL; + } + +@@ -1724,12 +2204,12 @@ + if ((cd->ctypes[c] & ctype_space) != 0) continue; + if (c == '#') + { +- while (*(++ptr) != 0) if (IS_NEWLINE(ptr)) break; +- if (*ptr != 0) ++ while (*(++ptr) != 0) + { +- ptr += cd->nllen - 1; +- continue; ++ if (IS_NEWLINE(ptr)) { ptr += cd->nllen - 1; break; } + } ++ if (*ptr != 0) continue; ++ + /* Else fall through to handle end of string */ + c = 0; + } +@@ -1745,17 +2225,23 @@ + + switch(c) + { +- /* The branch terminates at end of string, |, or ). */ +- +- case 0: +- case '|': ++ /* ===================================================================*/ ++ case 0: /* The branch terminates at string end */ ++ case '|': /* or | or ) */ + case ')': + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; + *codeptr = code; + *ptrptr = ptr; ++ if (lengthptr != NULL) ++ { ++ *lengthptr += code - last_code; /* To include callout length */ ++ DPRINTF((">> end branch\n")); ++ } + return TRUE; + ++ ++ /* ===================================================================*/ + /* Handle single-character metacharacters. In multiline mode, ^ disables + the setting of any following char as a first character. */ + +@@ -1784,6 +2270,8 @@ + *code++ = OP_ANY; + break; + ++ ++ /* ===================================================================*/ + /* Character classes. If the included characters are all < 256, we build a + 32-byte bitmap of the permitted characters, except in the special case + where there is only one such character. For negated classes, we build the +@@ -1822,32 +2310,32 @@ + } + + /* Keep a count of chars with values < 256 so that we can optimize the case +- of just a single character (as long as it's < 256). For higher valued UTF-8 +- characters, we don't yet do any optimization. */ ++ of just a single character (as long as it's < 256). However, For higher ++ valued UTF-8 characters, we don't yet do any optimization. */ + + class_charcount = 0; + class_lastchar = -1; + ++ /* 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 ++ than 256), because in that case the compiled code doesn't use the bit map. ++ */ ++ ++ memset(classbits, 0, 32 * sizeof(uschar)); ++ + #ifdef SUPPORT_UTF8 + class_utf8 = FALSE; /* No chars >= 256 */ +- class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ ++ class_utf8data = code + LINK_SIZE + 2; /* For UTF-8 items */ + #endif + +- /* Initialize the 32-char bit map to all zeros. We have to build the +- map in a temporary bit of store, in case the class contains only 1 +- character (< 256), because in that case the compiled code doesn't use the +- bit map. */ +- +- memset(classbits, 0, 32 * sizeof(uschar)); +- + /* Process characters until ] is reached. By writing this as a "do" it +- means that an initial ] is taken as a data character. The first pass +- through the regex checked the overall syntax, so we don't need to be very +- strict here. At the start of the loop, c contains the first byte of the +- character. */ ++ means that an initial ] is taken as a data character. At the start of the ++ loop, c contains the first byte of the character. */ + +- do ++ if (c != 0) do + { ++ const uschar *oldptr; ++ + #ifdef SUPPORT_UTF8 + if (utf8 && c > 127) + { /* Braces are required because the */ +@@ -1859,13 +2347,13 @@ + + if (inescq) + { +- if (c == '\\' && ptr[1] == 'E') ++ if (c == '\\' && ptr[1] == 'E') /* If we are at \E */ + { +- inescq = FALSE; +- ptr++; +- continue; ++ inescq = FALSE; /* Reset literal state */ ++ ptr++; /* Skip the 'E' */ ++ continue; /* Carry on with next */ + } +- else goto LONE_SINGLE_CHARACTER; ++ goto CHECK_RANGE; /* Could be range if \E follows */ + } + + /* Handle POSIX class names. Perl allows a negation extension of the +@@ -1956,19 +2444,20 @@ + } + + /* Backslash may introduce a single character, or it may introduce one +- of the specials, which just set a flag. Escaped items are checked for +- validity in the pre-compiling pass. The sequence \b is a special case. +- Inside a class (and only there) it is treated as backspace. Elsewhere +- it marks a word boundary. Other escapes have preset maps ready to +- or into the one we are building. We assume they have more than one ++ 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. ++ Elsewhere it marks a word boundary. Other escapes have preset maps ready ++ to or into the one we are building. We assume they have more than one + character in them, so set class_charcount bigger than one. */ + + if (c == '\\') + { +- c = check_escape(&ptr, errorcodeptr, *brackets, options, TRUE); ++ c = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); ++ if (*errorcodeptr != 0) goto FAILED; + + if (-c == ESC_b) c = '\b'; /* \b is backslash in a class */ + else if (-c == ESC_X) c = 'X'; /* \X is literal X in a class */ ++ else if (-c == ESC_R) c = 'R'; /* \R is literal R in a class */ + else if (-c == ESC_Q) /* Handle start of quoted string */ + { + if (ptr[1] == '\\' && ptr[2] == 'E') +@@ -1983,7 +2472,10 @@ + { + register const uschar *cbits = cd->cbits; + class_charcount += 2; /* Greater than 1 is what matters */ +- switch (-c) ++ ++ /* Save time by not doing this in the pre-compile phase. */ ++ ++ if (lengthptr == NULL) switch (-c) + { + case ESC_d: + for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; +@@ -2011,52 +2503,91 @@ + classbits[1] |= 0x08; /* Perl 5.004 onwards omits VT from \s */ + continue; + +-#ifdef SUPPORT_UCP +- case ESC_p: +- case ESC_P: +- { +- BOOL negated; +- int pdata; +- int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); +- if (ptype < 0) goto FAILED; +- class_utf8 = TRUE; +- *class_utf8data++ = ((-c == ESC_p) != negated)? +- XCL_PROP : XCL_NOTPROP; +- *class_utf8data++ = ptype; +- *class_utf8data++ = pdata; +- class_charcount -= 2; /* Not a < 256 character */ +- } ++ case ESC_E: /* Perl ignores an orphan \E */ + continue; +-#endif +- +- /* Unrecognized escapes are faulted if PCRE is running in its +- strict mode. By default, for compatibility with Perl, they are +- treated as literals. */ + +- default: +- if ((options & PCRE_EXTRA) != 0) +- { +- *errorcodeptr = ERR7; +- goto FAILED; +- } +- c = *ptr; /* The final character */ +- class_charcount -= 2; /* Undo the default count from above */ ++ default: /* Not recognized; fall through */ ++ break; /* Need "default" setting to stop compiler warning. */ + } +- } + +- /* Fall through if we have a single character (c >= 0). This may be +- > 256 in UTF-8 mode. */ ++ /* In the pre-compile phase, just do the recognition. */ + +- } /* End of backslash handling */ ++ else if (c == -ESC_d || c == -ESC_D || c == -ESC_w || ++ c == -ESC_W || c == -ESC_s || c == -ESC_S) continue; ++ ++ /* We need to deal with \P and \p in both phases. */ ++ ++#ifdef SUPPORT_UCP ++ if (-c == ESC_p || -c == ESC_P) ++ { ++ BOOL negated; ++ int pdata; ++ int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); ++ if (ptype < 0) goto FAILED; ++ class_utf8 = TRUE; ++ *class_utf8data++ = ((-c == ESC_p) != negated)? ++ XCL_PROP : XCL_NOTPROP; ++ *class_utf8data++ = ptype; ++ *class_utf8data++ = pdata; ++ class_charcount -= 2; /* Not a < 256 character */ ++ continue; ++ } ++#endif ++ /* Unrecognized escapes are faulted if PCRE is running in its ++ strict mode. By default, for compatibility with Perl, they are ++ treated as literals. */ ++ ++ if ((options & PCRE_EXTRA) != 0) ++ { ++ *errorcodeptr = ERR7; ++ goto FAILED; ++ } ++ ++ class_charcount -= 2; /* Undo the default count from above */ ++ c = *ptr; /* Get the final character and fall through */ ++ } ++ ++ /* Fall through if we have a single character (c >= 0). This may be ++ greater than 256 in UTF-8 mode. */ ++ ++ } /* End of backslash handling */ + + /* A single character may be followed by '-' to form a range. However, + Perl does not permit ']' to be the end of the range. A '-' character +- here is treated as a literal. */ ++ at the end is treated as a literal. Perl ignores orphaned \E sequences ++ entirely. The code for handling \Q and \E is messy. */ ++ ++ CHECK_RANGE: ++ while (ptr[1] == '\\' && ptr[2] == 'E') ++ { ++ inescq = FALSE; ++ ptr += 2; ++ } ++ ++ oldptr = ptr; + +- if (ptr[1] == '-' && ptr[2] != ']') ++ if (!inescq && ptr[1] == '-') + { + int d; + ptr += 2; ++ while (*ptr == '\\' && ptr[1] == 'E') ptr += 2; ++ ++ /* If we hit \Q (not followed by \E) at this point, go into escaped ++ mode. */ ++ ++ while (*ptr == '\\' && ptr[1] == 'Q') ++ { ++ ptr += 2; ++ if (*ptr == '\\' && ptr[1] == 'E') { ptr += 2; continue; } ++ inescq = TRUE; ++ break; ++ } ++ ++ if (*ptr == 0 || (!inescq && *ptr == ']')) ++ { ++ ptr = oldptr; ++ goto LONE_SINGLE_CHARACTER; ++ } + + #ifdef SUPPORT_UTF8 + if (utf8) +@@ -2071,27 +2602,34 @@ + not any of the other escapes. Perl 5.6 treats a hyphen as a literal + in such circumstances. */ + +- if (d == '\\') ++ if (!inescq && d == '\\') + { +- const uschar *oldptr = ptr; +- d = check_escape(&ptr, errorcodeptr, *brackets, options, TRUE); ++ d = check_escape(&ptr, errorcodeptr, cd->bracount, options, TRUE); ++ if (*errorcodeptr != 0) goto FAILED; + +- /* \b is backslash; \X is literal X; any other special means the '-' +- was literal */ ++ /* \b is backslash; \X is literal X; \R is literal R; any other ++ special means the '-' was literal */ + + if (d < 0) + { + if (d == -ESC_b) d = '\b'; +- else if (d == -ESC_X) d = 'X'; else ++ else if (d == -ESC_X) d = 'X'; ++ else if (d == -ESC_R) d = 'R'; else + { +- ptr = oldptr - 2; ++ ptr = oldptr; + goto LONE_SINGLE_CHARACTER; /* A few lines below */ + } + } + } + +- /* The check that the two values are in the correct order happens in +- the pre-pass. Optimize one-character ranges */ ++ /* Check that the two values are in the correct order. Optimize ++ one-character ranges */ ++ ++ if (d < c) ++ { ++ *errorcodeptr = ERR8; ++ goto FAILED; ++ } + + if (d == c) goto LONE_SINGLE_CHARACTER; /* A few lines below */ + +@@ -2112,9 +2650,9 @@ + #ifdef SUPPORT_UCP + if ((options & PCRE_CASELESS) != 0) + { +- int occ, ocd; +- int cc = c; +- int origd = d; ++ unsigned int occ, ocd; ++ unsigned int cc = c; ++ unsigned int origd = d; + while (get_othercase_range(&cc, origd, &occ, &ocd)) + { + if (occ >= c && ocd <= d) continue; /* Skip embedded ranges */ +@@ -2172,7 +2710,12 @@ + ranges that lie entirely within 0-127 when there is UCP support; else + for partial ranges without UCP support. */ + +- for (; c <= d; c++) ++ class_charcount += d - c + 1; ++ class_lastchar = d; ++ ++ /* We can save a bit of time by skipping this in the pre-compile. */ ++ ++ if (lengthptr == NULL) for (; c <= d; c++) + { + classbits[c/8] |= (1 << (c&7)); + if ((options & PCRE_CASELESS) != 0) +@@ -2180,8 +2723,6 @@ + int uc = cd->fcc[c]; /* flip case */ + classbits[uc/8] |= (1 << (uc&7)); + } +- class_charcount++; /* in case a one-char range */ +- class_lastchar = c; + } + + continue; /* Go get the next char in the class */ +@@ -2205,8 +2746,8 @@ + #ifdef SUPPORT_UCP + if ((options & PCRE_CASELESS) != 0) + { +- int othercase; +- if ((othercase = _pcre_ucp_othercase(c)) >= 0) ++ unsigned int othercase; ++ if ((othercase = _pcre_ucp_othercase(c)) != NOTACHAR) + { + *class_utf8data++ = XCL_SINGLE; + class_utf8data += _pcre_ord2utf8(othercase, class_utf8data); +@@ -2231,10 +2772,15 @@ + } + } + +- /* Loop until ']' reached; the check for end of string happens inside the +- loop. This "while" is the end of the "do" above. */ ++ /* Loop until ']' reached. This "while" is the end of the "do" above. */ + +- while ((c = *(++ptr)) != ']' || inescq); ++ while ((c = *(++ptr)) != 0 && (c != ']' || inescq)); ++ ++ if (c == 0) /* Missing terminating ']' */ ++ { ++ *errorcodeptr = ERR6; ++ goto FAILED; ++ } + + /* If class_charcount is 1, we saw precisely one character whose value is + less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we +@@ -2298,7 +2844,7 @@ + + /* If there are characters with values > 255, we have to compile an + extended class, with its own opcode. If there are no characters < 256, +- we can omit the bitmap. */ ++ we can omit the bitmap in the actual compiled code. */ + + #ifdef SUPPORT_UTF8 + if (class_utf8) +@@ -2308,24 +2854,17 @@ + code += LINK_SIZE; + *code = negate_class? XCL_NOT : 0; + +- /* If the map is required, install it, and move on to the end of +- the extra data */ ++ /* If the map is required, move up the extra data to make room for it; ++ otherwise just move the code pointer to the end of the extra data. */ + + if (class_charcount > 0) + { + *code++ |= XCL_MAP; ++ memmove(code + 32, code, class_utf8data - code); + memcpy(code, classbits, 32); +- code = class_utf8data; +- } +- +- /* If the map is not required, slide down the extra data. */ +- +- else +- { +- int len = class_utf8data - (code + 33); +- memmove(code + 1, code + 33, len); +- code += len + 1; ++ code = class_utf8data + 32; + } ++ else code = class_utf8data; + + /* Now fill in the complete length of the item */ + +@@ -2342,7 +2881,8 @@ + if (negate_class) + { + *code++ = OP_NCLASS; +- for (c = 0; c < 32; c++) code[c] = ~classbits[c]; ++ if (lengthptr == NULL) /* Save time in the pre-compile phase */ ++ for (c = 0; c < 32; c++) code[c] = ~classbits[c]; + } + else + { +@@ -2352,6 +2892,8 @@ + code += 32; + break; + ++ ++ /* ===================================================================*/ + /* Various kinds of repeat; '{' is not necessarily a quantifier, but this + has been tested above. */ + +@@ -2419,20 +2961,6 @@ + } + else repeat_type = greedy_default; + +- /* If previous was a recursion, we need to wrap it inside brackets so that +- it can be replicated if necessary. */ +- +- if (*previous == OP_RECURSE) +- { +- memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE); +- code += 1 + LINK_SIZE; +- *previous = OP_BRA; +- PUT(previous, 1, code - previous); +- *code = OP_KET; +- PUT(code, 1, code - previous); +- code += 1 + LINK_SIZE; +- } +- + /* If previous was a character match, abolish the item and generate a + repeat item instead. If a char item has a minumum of more than one, ensure + that it is set in reqbyte - it might not be if a sequence such as x{3} is +@@ -2466,18 +2994,40 @@ + if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt; + } + ++ /* If the repetition is unlimited, it pays to see if the next thing on ++ the line is something that cannot possibly match this character. If so, ++ automatically possessifying this item gains some performance in the case ++ where the match fails. */ ++ ++ if (!possessive_quantifier && ++ repeat_max < 0 && ++ check_auto_possessive(*previous, c, utf8, utf8_char, ptr + 1, ++ options, cd)) ++ { ++ repeat_type = 0; /* Force greedy */ ++ possessive_quantifier = TRUE; ++ } ++ + goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ + } + + /* If previous was a single negated character ([^a] or similar), we use + one of the special opcodes, replacing it. The code is shared with single- + character repeats by setting opt_type to add a suitable offset into +- repeat_type. OP_NOT is currently used only for single-byte chars. */ ++ repeat_type. We can also test for auto-possessification. OP_NOT is ++ currently used only for single-byte chars. */ + + else if (*previous == OP_NOT) + { + op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ + c = previous[1]; ++ if (!possessive_quantifier && ++ repeat_max < 0 && ++ check_auto_possessive(OP_NOT, c, utf8, NULL, ptr + 1, options, cd)) ++ { ++ repeat_type = 0; /* Force greedy */ ++ possessive_quantifier = TRUE; ++ } + goto OUTPUT_SINGLE_REPEAT; + } + +@@ -2495,6 +3045,14 @@ + op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ + c = *previous; + ++ if (!possessive_quantifier && ++ repeat_max < 0 && ++ check_auto_possessive(c, 0, utf8, NULL, ptr + 1, options, cd)) ++ { ++ repeat_type = 0; /* Force greedy */ ++ possessive_quantifier = TRUE; ++ } ++ + OUTPUT_SINGLE_REPEAT: + if (*previous == OP_PROP || *previous == OP_NOTPROP) + { +@@ -2535,7 +3093,7 @@ + } + + /* A repeat minimum of 1 is optimized into some special cases. If the +- maximum is unlimited, we use OP_PLUS. Otherwise, the original item it ++ maximum is unlimited, we use OP_PLUS. Otherwise, the original item is + left in place and, if the maximum is greater than 1, we use OP_UPTO with + one less than the maximum. */ + +@@ -2588,7 +3146,8 @@ + } + + /* Else insert an UPTO if the max is greater than the min, again +- preceded by the character, for the previously inserted code. */ ++ preceded by the character, for the previously inserted code. If the ++ UPTO is just for 1 instance, we can use QUERY instead. */ + + else if (repeat_max != repeat_min) + { +@@ -2607,8 +3166,16 @@ + *code++ = prop_value; + } + repeat_max -= repeat_min; +- *code++ = OP_UPTO + repeat_type; +- PUT2INC(code, 0, repeat_max); ++ ++ if (repeat_max == 1) ++ { ++ *code++ = OP_QUERY + repeat_type; ++ } ++ else ++ { ++ *code++ = OP_UPTO + repeat_type; ++ PUT2INC(code, 0, repeat_max); ++ } + } + } + +@@ -2675,14 +3242,30 @@ + /* If previous was a bracket group, we may have to replicate it in certain + cases. */ + +- else if (*previous >= OP_BRA || *previous == OP_ONCE || +- *previous == OP_COND) ++ else if (*previous == OP_BRA || *previous == OP_CBRA || ++ *previous == OP_ONCE || *previous == OP_COND) + { + register int i; + int ketoffset = 0; + int len = code - previous; + uschar *bralink = NULL; + ++ /* Repeating a DEFINE group is pointless */ ++ ++ if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_DEF) ++ { ++ *errorcodeptr = ERR55; ++ goto FAILED; ++ } ++ ++ /* This is a paranoid check to stop integer overflow later on */ ++ ++ if (len > MAX_DUPLENGTH) ++ { ++ *errorcodeptr = ERR50; ++ goto FAILED; ++ } ++ + /* If the maximum repeat count is unlimited, find the end of the bracket + by scanning through from the start, and compute the offset back to it + from the current code pointer. There may be an OP_OPT setting following +@@ -2717,13 +3300,14 @@ + /* If the maximum is 1 or unlimited, we just have to stick in the + BRAZERO and do no more at this point. However, we do need to adjust + any OP_RECURSE calls inside the group that refer to the group itself or +- any internal group, because the offset is from the start of the whole +- regex. Temporarily terminate the pattern while doing this. */ ++ any internal or forward referenced group, because the offset is from ++ the start of the whole regex. Temporarily terminate the pattern while ++ doing this. */ + + if (repeat_max <= 1) + { + *code = OP_END; +- adjust_recurse(previous, 1, utf8, cd); ++ adjust_recurse(previous, 1, utf8, cd, save_hwm); + memmove(previous+1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeat_type; +@@ -2741,7 +3325,7 @@ + { + int offset; + *code = OP_END; +- adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd); ++ adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd, save_hwm); + memmove(previous + 2 + LINK_SIZE, previous, len); + code += 2 + LINK_SIZE; + *previous++ = OP_BRAZERO + repeat_type; +@@ -2761,19 +3345,41 @@ + /* If the minimum is greater than zero, replicate the group as many + times as necessary, and adjust the maximum to the number of subsequent + copies that we need. If we set a first char from the group, and didn't +- set a required char, copy the latter from the former. */ ++ set a required char, copy the latter from the former. If there are any ++ forward reference subroutine calls in the group, there will be entries on ++ the workspace list; replicate these with an appropriate increment. */ + + else + { + if (repeat_min > 1) + { +- if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; +- for (i = 1; i < repeat_min; i++) ++ /* In the pre-compile phase, we don't actually do the replication. We ++ just adjust the length as if we had. */ ++ ++ if (lengthptr != NULL) ++ *lengthptr += (repeat_min - 1)*length_prevgroup; ++ ++ /* This is compiling for real */ ++ ++ else + { +- memcpy(code, previous, len); +- code += len; ++ if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; ++ for (i = 1; i < repeat_min; i++) ++ { ++ uschar *hc; ++ uschar *this_hwm = cd->hwm; ++ memcpy(code, previous, len); ++ for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) ++ { ++ PUT(cd->hwm, 0, GET(hc, 0) + len); ++ cd->hwm += LINK_SIZE; ++ } ++ save_hwm = this_hwm; ++ code += len; ++ } + } + } ++ + if (repeat_max > 0) repeat_max -= repeat_min; + } + +@@ -2781,12 +3387,27 @@ + the maximum is limited, it replicates the group in a nested fashion, + remembering the bracket starts on a stack. In the case of a zero minimum, + the first one was set up above. In all cases the repeat_max now specifies +- the number of additional copies needed. */ ++ the number of additional copies needed. Again, we must remember to ++ replicate entries on the forward reference list. */ + + if (repeat_max >= 0) + { +- for (i = repeat_max - 1; i >= 0; i--) ++ /* In the pre-compile phase, we don't actually do the replication. We ++ just adjust the length as if we had. For each repetition we must add 1 ++ to the length for BRAZERO and for all but the last repetition we must ++ add 2 + 2*LINKSIZE to allow for the nesting that occurs. */ ++ ++ if (lengthptr != NULL && repeat_max > 0) ++ *lengthptr += repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) - ++ 2 - 2*LINK_SIZE; /* Last one doesn't nest */ ++ ++ /* This is compiling for real */ ++ ++ else for (i = repeat_max - 1; i >= 0; i--) + { ++ uschar *hc; ++ uschar *this_hwm = cd->hwm; ++ + *code++ = OP_BRAZERO + repeat_type; + + /* All but the final copy start a new nesting, maintaining the +@@ -2802,6 +3423,12 @@ + } + + memcpy(code, previous, len); ++ for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) ++ { ++ PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); ++ cd->hwm += LINK_SIZE; ++ } ++ save_hwm = this_hwm; + code += len; + } + +@@ -2824,9 +3451,34 @@ + /* If the maximum is unlimited, set a repeater in the final copy. We + can't just offset backwards from the current code point, because we + don't know if there's been an options resetting after the ket. The +- correct offset was computed above. */ ++ correct offset was computed above. ++ ++ Then, when we are doing the actual compile phase, check to see whether ++ this group is a non-atomic one that could match an empty string. If so, ++ convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so ++ that runtime checking can be done. [This check is also applied to ++ atomic groups at runtime, but in a different way.] */ + +- else code[-ketoffset] = OP_KETRMAX + repeat_type; ++ else ++ { ++ uschar *ketcode = code - ketoffset; ++ uschar *bracode = ketcode - GET(ketcode, 1); ++ *ketcode = OP_KETRMAX + repeat_type; ++ if (lengthptr == NULL && *bracode != OP_ONCE) ++ { ++ uschar *scode = bracode; ++ do ++ { ++ if (could_be_empty_branch(scode, ketcode, utf8)) ++ { ++ *bracode += OP_SBRA - OP_BRA; ++ break; ++ } ++ scode += GET(scode, 1); ++ } ++ while (*scode == OP_ALT); ++ } ++ } + } + + /* Else there's some kind of shambles */ +@@ -2837,22 +3489,53 @@ + goto FAILED; + } + +- /* If the character following a repeat is '+', we wrap the entire repeated +- item inside OP_ONCE brackets. This is just syntactic sugar, taken from +- Sun's Java package. The repeated item starts at tempcode, not at previous, +- which might be the first part of a string whose (former) last char we +- repeated. However, we don't support '+' after a greediness '?'. */ ++ /* If the character following a repeat is '+', or if certain optimization ++ tests above succeeded, possessive_quantifier is TRUE. For some of the ++ simpler opcodes, there is an special alternative opcode for this. For ++ anything else, we wrap the entire repeated item inside OP_ONCE brackets. ++ The '+' notation is just syntactic sugar, taken from Sun's Java package, ++ but the special opcodes can optimize it a bit. The repeated item starts at ++ tempcode, not at previous, which might be the first part of a string whose ++ (former) last char we repeated. ++ ++ Possessifying an 'exact' quantifier has no effect, so we can ignore it. But ++ an 'upto' may follow. We skip over an 'exact' item, and then test the ++ length of what remains before proceeding. */ + + if (possessive_quantifier) + { +- int len = code - tempcode; +- memmove(tempcode + 1+LINK_SIZE, tempcode, len); +- code += 1 + LINK_SIZE; +- len += 1 + LINK_SIZE; +- tempcode[0] = OP_ONCE; +- *code++ = OP_KET; +- PUTINC(code, 0, len); +- PUT(tempcode, 1, len); ++ int len; ++ if (*tempcode == OP_EXACT || *tempcode == OP_TYPEEXACT || ++ *tempcode == OP_NOTEXACT) ++ tempcode += _pcre_OP_lengths[*tempcode]; ++ len = code - tempcode; ++ if (len > 0) switch (*tempcode) ++ { ++ case OP_STAR: *tempcode = OP_POSSTAR; break; ++ case OP_PLUS: *tempcode = OP_POSPLUS; break; ++ case OP_QUERY: *tempcode = OP_POSQUERY; break; ++ case OP_UPTO: *tempcode = OP_POSUPTO; break; ++ ++ case OP_TYPESTAR: *tempcode = OP_TYPEPOSSTAR; break; ++ case OP_TYPEPLUS: *tempcode = OP_TYPEPOSPLUS; break; ++ case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break; ++ case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break; ++ ++ case OP_NOTSTAR: *tempcode = OP_NOTPOSSTAR; break; ++ case OP_NOTPLUS: *tempcode = OP_NOTPOSPLUS; break; ++ case OP_NOTQUERY: *tempcode = OP_NOTPOSQUERY; break; ++ case OP_NOTUPTO: *tempcode = OP_NOTPOSUPTO; break; ++ ++ default: ++ memmove(tempcode + 1+LINK_SIZE, tempcode, len); ++ code += 1 + LINK_SIZE; ++ len += 1 + LINK_SIZE; ++ tempcode[0] = OP_ONCE; ++ *code++ = OP_KET; ++ PUTINC(code, 0, len); ++ PUT(tempcode, 1, len); ++ break; ++ } + } + + /* In all case we no longer have a previous item. We also set the +@@ -2865,162 +3548,275 @@ + break; + + +- /* Start of nested bracket sub-expression, or comment or lookahead or +- lookbehind or option setting or condition. First deal with special things +- that can come after a bracket; all are introduced by ?, and the appearance +- of any of them means that this is not a referencing group. They were +- checked for validity in the first pass over the string, so we don't have to +- check for syntax errors here. */ ++ /* ===================================================================*/ ++ /* Start of nested parenthesized sub-expression, or comment or lookahead or ++ lookbehind or option setting or condition or all the other extended ++ parenthesis forms. First deal with the specials; all are introduced by ?, ++ and the appearance of any of them means that this is not a capturing ++ group. */ + + case '(': + newoptions = options; + skipbytes = 0; ++ bravalue = OP_CBRA; ++ save_hwm = cd->hwm; + + if (*(++ptr) == '?') + { +- int set, unset; ++ int i, set, unset, namelen; + int *optset; ++ const uschar *name; ++ uschar *slot; + + switch (*(++ptr)) + { + case '#': /* Comment; skip to ket */ + ptr++; +- while (*ptr != ')') ptr++; ++ while (*ptr != 0 && *ptr != ')') ptr++; ++ if (*ptr == 0) ++ { ++ *errorcodeptr = ERR18; ++ goto FAILED; ++ } + continue; + +- case ':': /* Non-extracting bracket */ ++ ++ /* ------------------------------------------------------------ */ ++ case ':': /* Non-capturing bracket */ + bravalue = OP_BRA; + ptr++; + break; + ++ ++ /* ------------------------------------------------------------ */ + case '(': + bravalue = OP_COND; /* Conditional group */ + +- /* A condition can be a number, referring to a numbered group, a name, +- referring to a named group, 'R', referring to recursion, or an +- assertion. There are two unfortunate ambiguities, caused by history. +- (a) 'R' can be the recursive thing or the name 'R', 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 cases. If the first +- character after (?( is a word character, we know the rest up to ) will +- also be word characters because the syntax was checked in the first +- pass. */ +- +- if ((cd->ctypes[ptr[1]] & ctype_word) != 0) +- { +- int i, namelen; +- int condref = 0; +- const uschar *name; +- uschar *slot = cd->name_table; ++ /* A condition can be an assertion, a number (referring to a numbered ++ group), a name (referring to a named group), or 'R', referring to ++ recursion. R<digits> and R&name are also permitted for recursion tests. ++ ++ There are several syntaxes for testing a named group: (?(name)) is used ++ by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')). ++ ++ There are two unfortunate ambiguities, caused by history. (a) 'R' can ++ 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. ++ In both cases, we look for a name first; if not found, we try the other ++ cases. */ ++ ++ /* For conditions that are assertions, check the syntax, and then exit ++ the switch. This will take control down to where bracketed groups, ++ including assertions, are processed. */ + +- /* This is needed for all successful cases. */ ++ if (ptr[1] == '?' && (ptr[2] == '=' || ptr[2] == '!' || ptr[2] == '<')) ++ break; + +- skipbytes = 3; ++ /* Most other conditions use OP_CREF (a couple change to OP_RREF ++ below), and all need to skip 3 bytes at the start of the group. */ + +- /* Read the name, but also get it as a number if it's all digits */ ++ code[1+LINK_SIZE] = OP_CREF; ++ skipbytes = 3; + +- name = ++ptr; +- while (*ptr != ')') +- { +- if (condref >= 0) +- condref = ((digitab[*ptr] & ctype_digit) != 0)? +- condref * 10 + *ptr - '0' : -1; +- ptr++; +- } +- namelen = ptr - name; ++ /* Check for a test for recursion in a named group. */ ++ ++ if (ptr[1] == 'R' && ptr[2] == '&') ++ { ++ terminator = -1; ++ ptr += 2; ++ code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ ++ } ++ ++ /* Check for a test for a named group's having been set, using the Perl ++ syntax (?(<name>) or (?('name') */ ++ ++ else if (ptr[1] == '<') ++ { ++ terminator = '>'; + ptr++; ++ } ++ else if (ptr[1] == '\'') ++ { ++ terminator = '\''; ++ ptr++; ++ } ++ else terminator = 0; + +- for (i = 0; i < cd->names_found; i++) +- { +- if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; +- slot += cd->name_entry_size; +- } ++ /* We now expect to read a name; any thing else is an error */ + +- /* Found a previous named subpattern */ ++ if ((cd->ctypes[ptr[1]] & ctype_word) == 0) ++ { ++ ptr += 1; /* To get the right offset */ ++ *errorcodeptr = ERR28; ++ goto FAILED; ++ } + +- if (i < cd->names_found) +- { +- condref = GET2(slot, 0); +- code[1+LINK_SIZE] = OP_CREF; +- PUT2(code, 2+LINK_SIZE, condref); +- } ++ /* Read the name, but also get it as a number if it's all digits */ + +- /* Search the pattern for a forward reference */ ++ recno = 0; ++ name = ++ptr; ++ while ((cd->ctypes[*ptr] & ctype_word) != 0) ++ { ++ if (recno >= 0) ++ recno = ((digitab[*ptr] & ctype_digit) != 0)? ++ recno * 10 + *ptr - '0' : -1; ++ ptr++; ++ } ++ namelen = ptr - name; + +- else if ((i = find_named_parens(ptr, *brackets, name, namelen)) > 0) +- { +- code[1+LINK_SIZE] = OP_CREF; +- PUT2(code, 2+LINK_SIZE, i); +- } ++ if ((terminator > 0 && *ptr++ != terminator) || *ptr++ != ')') ++ { ++ ptr--; /* Error offset */ ++ *errorcodeptr = ERR26; ++ goto FAILED; ++ } + +- /* Check for 'R' for recursion */ ++ /* Do no further checking in the pre-compile phase. */ + +- else if (namelen == 1 && *name == 'R') +- { +- code[1+LINK_SIZE] = OP_CREF; +- PUT2(code, 2+LINK_SIZE, CREF_RECURSE); +- } ++ if (lengthptr != NULL) break; + +- /* Check for a subpattern number */ ++ /* In the real compile we do the work of looking for the actual ++ reference. */ + +- else if (condref > 0) +- { +- code[1+LINK_SIZE] = OP_CREF; +- PUT2(code, 2+LINK_SIZE, condref); +- } ++ slot = cd->name_table; ++ for (i = 0; i < cd->names_found; i++) ++ { ++ if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; ++ slot += cd->name_entry_size; ++ } + +- /* Either an unidentified subpattern, or a reference to (?(0) */ ++ /* Found a previous named subpattern */ + +- else ++ if (i < cd->names_found) ++ { ++ recno = GET2(slot, 0); ++ PUT2(code, 2+LINK_SIZE, recno); ++ } ++ ++ /* Search the pattern for a forward reference */ ++ ++ else if ((i = find_parens(ptr, cd->bracount, name, namelen, ++ (options & PCRE_EXTENDED) != 0)) > 0) ++ { ++ PUT2(code, 2+LINK_SIZE, i); ++ } ++ ++ /* If terminator == 0 it means that the name followed directly after ++ the opening parenthesis [e.g. (?(abc)...] and in this case there are ++ some further alternatives to try. For the cases where terminator != 0 ++ [things like (?(<name>... or (?('name')... or (?(R&name)... ] we have ++ now checked all the possibilities, so give an error. */ ++ ++ else if (terminator != 0) ++ { ++ *errorcodeptr = ERR15; ++ goto FAILED; ++ } ++ ++ /* Check for (?(R) for recursion. Allow digits after R to specify a ++ specific group number. */ ++ ++ else if (*name == 'R') ++ { ++ recno = 0; ++ for (i = 1; i < namelen; i++) + { +- *errorcodeptr = (condref == 0)? ERR35: ERR15; +- goto FAILED; ++ if ((digitab[name[i]] & ctype_digit) == 0) ++ { ++ *errorcodeptr = ERR15; ++ goto FAILED; ++ } ++ recno = recno * 10 + name[i] - '0'; + } ++ if (recno == 0) recno = RREF_ANY; ++ code[1+LINK_SIZE] = OP_RREF; /* Change test type */ ++ PUT2(code, 2+LINK_SIZE, recno); ++ } ++ ++ /* Similarly, check for the (?(DEFINE) "condition", which is always ++ false. */ ++ ++ else if (namelen == 6 && strncmp((char *)name, "DEFINE", 6) == 0) ++ { ++ code[1+LINK_SIZE] = OP_DEF; ++ skipbytes = 1; ++ } ++ ++ /* Check for the "name" actually being a subpattern number. */ ++ ++ else if (recno > 0) ++ { ++ PUT2(code, 2+LINK_SIZE, recno); + } + +- /* For conditions that are assertions, we just fall through, having +- set bravalue above. */ ++ /* Either an unidentified subpattern, or a reference to (?(0) */ + ++ else ++ { ++ *errorcodeptr = (recno == 0)? ERR35: ERR15; ++ goto FAILED; ++ } + break; + ++ ++ /* ------------------------------------------------------------ */ + case '=': /* Positive lookahead */ + bravalue = OP_ASSERT; + ptr++; + break; + ++ ++ /* ------------------------------------------------------------ */ + case '!': /* Negative lookahead */ + bravalue = OP_ASSERT_NOT; + ptr++; + break; + +- case '<': /* Lookbehinds */ +- switch (*(++ptr)) ++ ++ /* ------------------------------------------------------------ */ ++ case '<': /* Lookbehind or named define */ ++ switch (ptr[1]) + { + case '=': /* Positive lookbehind */ + bravalue = OP_ASSERTBACK; +- ptr++; ++ ptr += 2; + break; + + case '!': /* Negative lookbehind */ + bravalue = OP_ASSERTBACK_NOT; +- ptr++; ++ ptr += 2; + break; ++ ++ default: /* Could be name define, else bad */ ++ if ((cd->ctypes[ptr[1]] & ctype_word) != 0) goto DEFINE_NAME; ++ ptr++; /* Correct offset for error */ ++ *errorcodeptr = ERR24; ++ goto FAILED; + } + break; + ++ ++ /* ------------------------------------------------------------ */ + case '>': /* One-time brackets */ + bravalue = OP_ONCE; + ptr++; + break; + ++ ++ /* ------------------------------------------------------------ */ + case 'C': /* Callout - may be followed by digits; */ + previous_callout = code; /* Save for later completion */ + after_manual_callout = 1; /* Skip one item before completing */ +- *code++ = OP_CALLOUT; /* Already checked that the terminating */ +- { /* closing parenthesis is present. */ ++ *code++ = OP_CALLOUT; ++ { + int n = 0; + while ((digitab[*(++ptr)] & ctype_digit) != 0) + n = n * 10 + *ptr - '0'; ++ if (*ptr != ')') ++ { ++ *errorcodeptr = ERR39; ++ goto FAILED; ++ } + if (n > 255) + { + *errorcodeptr = ERR38; +@@ -3034,134 +3830,232 @@ + previous = NULL; + continue; + +- case 'P': /* Named subpattern handling */ +- if (*(++ptr) == '<') /* Definition */ ++ ++ /* ------------------------------------------------------------ */ ++ case 'P': /* Python-style named subpattern handling */ ++ if (*(++ptr) == '=' || *ptr == '>') /* Reference or recursion */ ++ { ++ is_recurse = *ptr == '>'; ++ terminator = ')'; ++ goto NAMED_REF_OR_RECURSE; ++ } ++ else if (*ptr != '<') /* Test for Python-style definition */ ++ { ++ *errorcodeptr = ERR41; ++ goto FAILED; ++ } ++ /* Fall through to handle (?P< as (?< is handled */ ++ ++ ++ /* ------------------------------------------------------------ */ ++ DEFINE_NAME: /* Come here from (?< handling */ ++ case '\'': + { +- int i, namelen; +- uschar *slot = cd->name_table; +- const uschar *name; /* Don't amalgamate; some compilers */ +- name = ++ptr; /* grumble at autoincrement in declaration */ ++ terminator = (*ptr == '<')? '>' : '\''; ++ name = ++ptr; ++ ++ while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; ++ namelen = ptr - name; + +- while (*ptr++ != '>'); +- namelen = ptr - name - 1; ++ /* In the pre-compile phase, just do a syntax check. */ + +- for (i = 0; i < cd->names_found; i++) ++ if (lengthptr != NULL) ++ { ++ if (*ptr != terminator) ++ { ++ *errorcodeptr = ERR42; ++ goto FAILED; ++ } ++ if (cd->names_found >= MAX_NAME_COUNT) ++ { ++ *errorcodeptr = ERR49; ++ goto FAILED; ++ } ++ if (namelen + 3 > cd->name_entry_size) ++ { ++ cd->name_entry_size = namelen + 3; ++ if (namelen > MAX_NAME_SIZE) ++ { ++ *errorcodeptr = ERR48; ++ goto FAILED; ++ } ++ } ++ } ++ ++ /* In the real compile, create the entry in the table */ ++ ++ else + { +- int crc = memcmp(name, slot+2, namelen); +- if (crc == 0) ++ slot = cd->name_table; ++ for (i = 0; i < cd->names_found; i++) + { +- if (slot[2+namelen] == 0) ++ int crc = memcmp(name, slot+2, namelen); ++ if (crc == 0) + { +- if ((options & PCRE_DUPNAMES) == 0) ++ if (slot[2+namelen] == 0) + { +- *errorcodeptr = ERR43; +- goto FAILED; ++ if ((options & PCRE_DUPNAMES) == 0) ++ { ++ *errorcodeptr = ERR43; ++ goto FAILED; ++ } + } ++ else crc = -1; /* Current name is substring */ + } +- else crc = -1; /* Current name is substring */ +- } +- if (crc < 0) +- { +- memmove(slot + cd->name_entry_size, slot, +- (cd->names_found - i) * cd->name_entry_size); +- break; ++ if (crc < 0) ++ { ++ memmove(slot + cd->name_entry_size, slot, ++ (cd->names_found - i) * cd->name_entry_size); ++ break; ++ } ++ slot += cd->name_entry_size; + } +- slot += cd->name_entry_size; +- } + +- PUT2(slot, 0, *brackets + 1); +- memcpy(slot + 2, name, namelen); +- slot[2+namelen] = 0; +- cd->names_found++; +- goto NUMBERED_GROUP; ++ PUT2(slot, 0, cd->bracount + 1); ++ memcpy(slot + 2, name, namelen); ++ slot[2+namelen] = 0; ++ } + } + +- if (*ptr == '=' || *ptr == '>') /* Reference or recursion */ +- { +- int i, namelen; +- int type = *ptr++; +- const uschar *name = ptr; +- uschar *slot = cd->name_table; ++ /* In both cases, count the number of names we've encountered. */ + +- while (*ptr != ')') ptr++; +- namelen = ptr - name; ++ ptr++; /* Move past > or ' */ ++ cd->names_found++; ++ goto NUMBERED_GROUP; + +- for (i = 0; i < cd->names_found; i++) ++ ++ /* ------------------------------------------------------------ */ ++ case '&': /* Perl recursion/subroutine syntax */ ++ terminator = ')'; ++ is_recurse = TRUE; ++ /* Fall through */ ++ ++ /* We come here from the Python syntax above that handles both ++ references (?P=name) and recursion (?P>name), as well as falling ++ through from the Perl recursion syntax (?&name). */ ++ ++ NAMED_REF_OR_RECURSE: ++ name = ++ptr; ++ while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; ++ namelen = ptr - name; ++ ++ /* In the pre-compile phase, do a syntax check and set a dummy ++ reference number. */ ++ ++ if (lengthptr != NULL) ++ { ++ if (*ptr != terminator) + { +- if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; +- slot += cd->name_entry_size; ++ *errorcodeptr = ERR42; ++ goto FAILED; + } +- +- if (i < cd->names_found) /* Back reference */ ++ if (namelen > MAX_NAME_SIZE) ++ { ++ *errorcodeptr = ERR48; ++ goto FAILED; ++ } ++ recno = 0; ++ } ++ ++ /* In the real compile, seek the name in the table */ ++ ++ else ++ { ++ slot = cd->name_table; ++ for (i = 0; i < cd->names_found; i++) ++ { ++ if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break; ++ slot += cd->name_entry_size; ++ } ++ ++ if (i < cd->names_found) /* Back reference */ + { + recno = GET2(slot, 0); + } + else if ((recno = /* Forward back reference */ +- find_named_parens(ptr, *brackets, name, namelen)) <= 0) ++ find_parens(ptr, cd->bracount, name, namelen, ++ (options & PCRE_EXTENDED) != 0)) <= 0) + { + *errorcodeptr = ERR15; + goto FAILED; + } ++ } + +- if (type == '>') goto HANDLE_RECURSION; /* A few lines below */ +- +- /* Back reference */ ++ /* In both phases, we can now go to the code than handles numerical ++ recursion or backreferences. */ + +- previous = code; +- *code++ = OP_REF; +- PUT2INC(code, 0, recno); +- cd->backref_map |= (recno < 32)? (1 << recno) : 1; +- if (recno > cd->top_backref) cd->top_backref = recno; +- continue; +- } ++ if (is_recurse) goto HANDLE_RECURSION; ++ else goto HANDLE_REFERENCE; + +- /* Should never happen */ +- break; + +- case 'R': /* Pattern recursion */ ++ /* ------------------------------------------------------------ */ ++ case 'R': /* Recursion */ + ptr++; /* Same as (?0) */ + /* Fall through */ + +- /* Recursion or "subroutine" call */ + +- case '0': case '1': case '2': case '3': case '4': +- case '5': case '6': case '7': case '8': case '9': ++ /* ------------------------------------------------------------ */ ++ case '0': case '1': case '2': case '3': case '4': /* Recursion or */ ++ case '5': case '6': case '7': case '8': case '9': /* subroutine */ + { + const uschar *called; + recno = 0; + while((digitab[*ptr] & ctype_digit) != 0) + recno = recno * 10 + *ptr++ - '0'; ++ if (*ptr != ')') ++ { ++ *errorcodeptr = ERR29; ++ goto FAILED; ++ } + + /* Come here from code above that handles a named recursion */ + + HANDLE_RECURSION: + + previous = code; ++ called = cd->start_code; + +- /* Find the bracket that is being referenced. Temporarily end the +- regex in case it doesn't exist. */ ++ /* When we are actually compiling, find the bracket that is being ++ referenced. Temporarily end the regex in case it doesn't exist before ++ this point. If we end up with a forward reference, first check that ++ the bracket does occur later so we can give the error (and position) ++ now. Then remember this forward reference in the workspace so it can ++ be filled in at the end. */ + +- *code = OP_END; +- called = (recno == 0)? cd->start_code : +- find_bracket(cd->start_code, utf8, recno); +- if (called == NULL) ++ if (lengthptr == NULL) + { +- *errorcodeptr = ERR15; +- goto FAILED; +- } ++ *code = OP_END; ++ if (recno != 0) called = find_bracket(cd->start_code, utf8, recno); + +- /* If the subpattern is still open, this is a recursive call. We +- check to see if this is a left recursion that could loop for ever, +- and diagnose that case. */ ++ /* Forward reference */ + +- if (GET(called, 1) == 0 && could_be_empty(called, code, bcptr, utf8)) +- { +- *errorcodeptr = ERR40; +- goto FAILED; ++ if (called == NULL) ++ { ++ if (find_parens(ptr, cd->bracount, NULL, recno, ++ (options & PCRE_EXTENDED) != 0) < 0) ++ { ++ *errorcodeptr = ERR15; ++ goto FAILED; ++ } ++ called = cd->start_code + recno; ++ PUTINC(cd->hwm, 0, code + 2 + LINK_SIZE - cd->start_code); ++ } ++ ++ /* If not a forward reference, and the subpattern is still open, ++ this is a recursive call. We check to see if this is a left ++ recursion that could loop for ever, and diagnose that case. */ ++ ++ else if (GET(called, 1) == 0 && ++ could_be_empty(called, code, bcptr, utf8)) ++ { ++ *errorcodeptr = ERR40; ++ goto FAILED; ++ } + } + + /* Insert the recursion/subroutine item, automatically wrapped inside +- "once" brackets. */ ++ "once" brackets. Set up a "previous group" length so that a ++ subsequent quantifier will work. */ + + *code = OP_ONCE; + PUT(code, 1, 2 + 2*LINK_SIZE); +@@ -3174,12 +4068,18 @@ + *code = OP_KET; + PUT(code, 1, 2 + 2*LINK_SIZE); + code += 1 + LINK_SIZE; ++ ++ length_prevgroup = 3 + 3*LINK_SIZE; + } ++ ++ /* Can't determine a first byte now */ ++ ++ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + continue; + +- /* Character after (? not specially recognized */ + +- default: /* Option setting */ ++ /* ------------------------------------------------------------ */ ++ default: /* Other characters: check option setting */ + set = unset = 0; + optset = &set; + +@@ -3189,13 +4089,21 @@ + { + case '-': optset = &unset; break; + ++ case 'J': /* Record that it changed in the external options */ ++ *optset |= PCRE_DUPNAMES; ++ cd->external_options |= PCRE_JCHANGED; ++ break; ++ + case 'i': *optset |= PCRE_CASELESS; break; +- case 'J': *optset |= PCRE_DUPNAMES; break; + case 'm': *optset |= PCRE_MULTILINE; break; + case 's': *optset |= PCRE_DOTALL; break; + case 'x': *optset |= PCRE_EXTENDED; break; + case 'U': *optset |= PCRE_UNGREEDY; break; + case 'X': *optset |= PCRE_EXTRA; break; ++ ++ default: *errorcodeptr = ERR12; ++ ptr--; /* Correct the offset */ ++ goto FAILED; + } + } + +@@ -3204,32 +4112,54 @@ + newoptions = (options | set) & (~unset); + + /* If the options ended with ')' this is not the start of a nested +- group with option changes, so the options change at this level. Compile +- code to change the ims options if this setting actually changes any of +- them. We also pass the new setting back so that it can be put at the +- start of any following branches, and when this group ends (if we are in +- a group), a resetting item can be compiled. +- +- Note that if this item is right at the start of the pattern, the +- options will have been abstracted and made global, so there will be no +- change to compile. */ ++ group with option changes, so the options change at this level. If this ++ item is right at the start of the pattern, the options can be ++ abstracted and made external in the pre-compile phase, and ignored in ++ the compile phase. This can be helpful when matching -- for instance in ++ caseless checking of required bytes. ++ ++ If the code pointer is not (cd->start_code + 1 + LINK_SIZE), we are ++ definitely *not* at the start of the pattern because something has been ++ compiled. In the pre-compile phase, however, the code pointer can have ++ that value after the start, because it gets reset as code is discarded ++ during the pre-compile. However, this can happen only at top level - if ++ we are within parentheses, the starting BRA will still be present. At ++ any parenthesis level, the length value can be used to test if anything ++ has been compiled at that level. Thus, a test for both these conditions ++ is necessary to ensure we correctly detect the start of the pattern in ++ both phases. ++ ++ If we are not at the pattern start, compile code to change the ims ++ options if this setting actually changes any of them. We also pass the ++ new setting back so that it can be put at the start of any following ++ branches, and when this group ends (if we are in a group), a resetting ++ item can be compiled. */ + + if (*ptr == ')') + { +- if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) ++ if (code == cd->start_code + 1 + LINK_SIZE && ++ (lengthptr == NULL || *lengthptr == 2 + 2*LINK_SIZE)) + { +- *code++ = OP_OPT; +- *code++ = newoptions & PCRE_IMS; ++ cd->external_options = newoptions; ++ options = newoptions; + } ++ else ++ { ++ if ((options & PCRE_IMS) != (newoptions & PCRE_IMS)) ++ { ++ *code++ = OP_OPT; ++ *code++ = newoptions & PCRE_IMS; ++ } + +- /* Change options at this level, and pass them back for use +- in subsequent branches. Reset the greedy defaults and the case +- value for firstbyte and reqbyte. */ +- +- *optionsptr = options = newoptions; +- greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); +- greedy_non_default = greedy_default ^ 1; +- req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; ++ /* Change options at this level, and pass them back for use ++ in subsequent branches. Reset the greedy defaults and the case ++ value for firstbyte and reqbyte. */ ++ ++ *optionsptr = options = newoptions; ++ greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); ++ greedy_non_default = greedy_default ^ 1; ++ req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0; ++ } + + previous = NULL; /* This item can't be repeated */ + continue; /* It is complete */ +@@ -3242,58 +4172,56 @@ + + bravalue = OP_BRA; + ptr++; +- } +- } ++ } /* End of switch for character following (? */ ++ } /* End of (? handling */ + +- /* If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become +- non-capturing and behave like (?:...) brackets */ ++ /* Opening parenthesis not followed by '?'. If PCRE_NO_AUTO_CAPTURE is set, ++ all unadorned brackets become non-capturing and behave like (?:...) ++ brackets. */ + + else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) + { + bravalue = OP_BRA; + } + +- /* Else we have a referencing group; adjust the opcode. If the bracket +- number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and +- arrange for the true number to follow later, in an OP_BRANUMBER item. */ ++ /* Else we have a capturing group. */ + + else + { + NUMBERED_GROUP: +- if (++(*brackets) > EXTRACT_BASIC_MAX) +- { +- bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; +- code[1+LINK_SIZE] = OP_BRANUMBER; +- PUT2(code, 2+LINK_SIZE, *brackets); +- skipbytes = 3; +- } +- else bravalue = OP_BRA + *brackets; ++ cd->bracount += 1; ++ PUT2(code, 1+LINK_SIZE, cd->bracount); ++ skipbytes = 2; + } + +- /* Process nested bracketed re. Assertions may not be repeated, but other +- kinds can be. We copy code into a non-register variable in order to be able +- to pass its address because some compilers complain otherwise. Pass in a +- new setting for the ims options if they have changed. */ ++ /* Process nested bracketed regex. Assertions may not be repeated, but ++ other kinds can be. All their opcodes are >= OP_ONCE. We copy code into a ++ non-register variable in order to be able to pass its address because some ++ compilers complain otherwise. Pass in a new setting for the ims options if ++ they have changed. */ + + previous = (bravalue >= OP_ONCE)? code : NULL; + *code = bravalue; + tempcode = code; + tempreqvary = cd->req_varyopt; /* Save value before bracket */ ++ length_prevgroup = 0; /* Initialize for pre-compile phase */ + + if (!compile_regex( + newoptions, /* The complete new option state */ + options & PCRE_IMS, /* The previous ims option state */ +- brackets, /* Extracting bracket count */ + &tempcode, /* Where to put code (updated) */ + &ptr, /* Input pointer (updated) */ + errorcodeptr, /* Where to put an error message */ + (bravalue == OP_ASSERTBACK || + bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ +- skipbytes, /* Skip over OP_COND/OP_BRANUMBER */ ++ skipbytes, /* Skip over bracket number */ + &subfirstbyte, /* For possible first char */ + &subreqbyte, /* For possible last char */ + bcptr, /* Current branch chain */ +- cd)) /* Tables block */ ++ cd, /* Tables block */ ++ (lengthptr == NULL)? NULL : /* Actual compile phase */ ++ &length_prevgroup /* Pre-compile phase */ ++ )) + goto FAILED; + + /* At the end of compiling, code is still pointing to the start of the +@@ -3302,9 +4230,9 @@ + is on the bracket. */ + + /* If this is a conditional bracket, check that there are no more than +- two branches in the group. */ ++ two branches in the group, or just one if it's a DEFINE group. */ + +- else if (bravalue == OP_COND) ++ if (bravalue == OP_COND) + { + uschar *tc = code; + int condcount = 0; +@@ -3315,29 +4243,77 @@ + } + while (*tc != OP_KET); + +- if (condcount > 2) ++ /* A DEFINE group is never obeyed inline (the "condition" is always ++ false). It must have only one branch. */ ++ ++ if (code[LINK_SIZE+1] == OP_DEF) + { +- *errorcodeptr = ERR27; +- goto FAILED; ++ if (condcount > 1) ++ { ++ *errorcodeptr = ERR54; ++ goto FAILED; ++ } ++ bravalue = OP_DEF; /* Just a flag to suppress char handling below */ ++ } ++ ++ /* A "normal" conditional group. If there is just one branch, we must not ++ make use of its firstbyte or reqbyte, because this is equivalent to an ++ empty second branch. */ ++ ++ else ++ { ++ if (condcount > 2) ++ { ++ *errorcodeptr = ERR27; ++ goto FAILED; ++ } ++ if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; + } ++ } ++ ++ /* Error if hit end of pattern */ + +- /* If there is just one branch, we must not make use of its firstbyte or +- reqbyte, because this is equivalent to an empty second branch. */ ++ if (*ptr != ')') ++ { ++ *errorcodeptr = ERR14; ++ goto FAILED; ++ } + +- if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE; ++ /* In the pre-compile phase, update the length by the length of the nested ++ group, less the brackets at either end. Then reduce the compiled code to ++ just the brackets so that it doesn't use much memory if it is duplicated by ++ a quantifier. */ ++ ++ if (lengthptr != NULL) ++ { ++ *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; ++ code++; ++ PUTINC(code, 0, 1 + LINK_SIZE); ++ *code++ = OP_KET; ++ PUTINC(code, 0, 1 + LINK_SIZE); + } + +- /* Handle updating of the required and first characters. Update for normal +- brackets of all kinds, and conditions with two branches (see code above). +- If the bracket is followed by a quantifier with zero repeat, we have to +- back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the +- main loop so that they can be accessed for the back off. */ ++ /* Otherwise update the main code pointer to the end of the group. */ ++ ++ else code = tempcode; ++ ++ /* For a DEFINE group, required and first character settings are not ++ relevant. */ ++ ++ if (bravalue == OP_DEF) break; ++ ++ /* Handle updating of the required and first characters for other types of ++ group. Update for normal brackets of all kinds, and conditions with two ++ branches (see code above). If the bracket is followed by a quantifier with ++ zero repeat, we have to back off. Hence the definition of zeroreqbyte and ++ zerofirstbyte outside the main loop so that they can be accessed for the ++ back off. */ + + zeroreqbyte = reqbyte; + zerofirstbyte = firstbyte; + groupsetfirstbyte = FALSE; + +- if (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_COND) ++ if (bravalue >= OP_ONCE) + { + /* If we have not yet set a firstbyte in this branch, take it from the + subpattern, remembering that it was set here so that a repeat of more +@@ -3378,35 +4354,22 @@ + firstbyte, looking for an asserted first char. */ + + else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte; ++ break; /* End of processing '(' */ + +- /* Now update the main code pointer to the end of the group. */ +- +- code = tempcode; +- +- /* Error if hit end of pattern */ +- +- if (*ptr != ')') +- { +- *errorcodeptr = ERR14; +- goto FAILED; +- } +- break; +- +- /* Check \ for being a real metacharacter; if not, fall through and handle +- it as a data character at the start of a string. Escape items are checked +- for validity in the pre-compiling pass. */ +- +- case '\\': +- tempptr = ptr; +- c = check_escape(&ptr, errorcodeptr, *brackets, options, FALSE); + +- /* Handle metacharacters 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. For the + back references, the values are ESC_REF plus the reference number. Only + back references and those types 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 ever created. */ + ++ case '\\': ++ tempptr = ptr; ++ c = check_escape(&ptr, errorcodeptr, cd->bracount, options, FALSE); ++ if (*errorcodeptr != 0) goto FAILED; ++ + if (c < 0) + { + if (-c == ESC_Q) /* Handle start of quoted string */ +@@ -3416,6 +4379,8 @@ + continue; + } + ++ if (-c == ESC_E) continue; /* Perl ignores an orphan \E */ ++ + /* For metasequences that actually match a character, we disable the + setting of a first character if it hasn't already been set. */ + +@@ -3427,18 +4392,33 @@ + zerofirstbyte = firstbyte; + zeroreqbyte = reqbyte; + +- /* Back references are handled specially */ ++ /* \k<name> or \k'name' is a back reference by name (Perl syntax) */ ++ ++ if (-c == ESC_k && (ptr[1] == '<' || ptr[1] == '\'')) ++ { ++ is_recurse = FALSE; ++ terminator = (*(++ptr) == '<')? '>' : '\''; ++ goto NAMED_REF_OR_RECURSE; ++ } ++ ++ /* Back references are handled specially; must disable firstbyte if ++ not set to cope with cases like (?=(\w+))\1: which would otherwise set ++ ':' later. */ + + if (-c >= ESC_REF) + { +- int number = -c - ESC_REF; ++ recno = -c - ESC_REF; ++ ++ HANDLE_REFERENCE: /* Come here from named backref handling */ ++ if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE; + previous = code; + *code++ = OP_REF; +- PUT2INC(code, 0, number); ++ PUT2INC(code, 0, recno); ++ cd->backref_map |= (recno < 32)? (1 << recno) : 1; ++ if (recno > cd->top_backref) cd->top_backref = recno; + } + +- /* So are Unicode property matches, if supported. We know that get_ucp +- won't fail because it was tested in the pre-pass. */ ++ /* So are Unicode property matches, if supported. */ + + #ifdef SUPPORT_UCP + else if (-c == ESC_P || -c == ESC_p) +@@ -3446,15 +4426,26 @@ + BOOL negated; + int pdata; + int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr); ++ if (ptype < 0) goto FAILED; + previous = code; + *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP; + *code++ = ptype; + *code++ = pdata; + } ++#else ++ ++ /* If Unicode properties are not supported, \X, \P, and \p are not ++ allowed. */ ++ ++ else if (-c == ESC_X || -c == ESC_P || -c == ESC_p) ++ { ++ *errorcodeptr = ERR45; ++ goto FAILED; ++ } + #endif + +- /* For the rest, we can obtain the OP value by negating the escape +- value */ ++ /* For the rest (including \X when Unicode properties are supported), we ++ can obtain the OP value by negating the escape value. */ + + else + { +@@ -3478,9 +4469,10 @@ + mcbuffer[0] = c; + mclength = 1; + } +- + goto ONE_CHAR; + ++ ++ /* ===================================================================*/ + /* Handle a literal character. It is guaranteed not to be whitespace or # + when the extended flag is set. If we are in UTF-8 mode, it may be a + multi-byte literal character. */ +@@ -3491,7 +4483,7 @@ + mcbuffer[0] = c; + + #ifdef SUPPORT_UTF8 +- if (utf8 && (c & 0xc0) == 0xc0) ++ if (utf8 && c >= 0xc0) + { + while ((ptr[1] & 0xc0) == 0x80) + mcbuffer[mclength++] = *(++ptr); +@@ -3542,6 +4534,7 @@ + } + } /* end of big loop */ + ++ + /* Control never reaches here by falling through, only by a goto for all the + error states. Pass back the position in the pattern so that it can be displayed + to the user for diagnosing the error. */ +@@ -3558,35 +4551,40 @@ + * Compile sequence of alternatives * + *************************************************/ + +-/* On entry, ptr is pointing past the bracket character, but on return +-it points to the closing bracket, or vertical bar, or end of string. +-The code variable is pointing at the byte into which the BRA operator has been +-stored. If the ims options are changed at the start (for a (?ims: group) or +-during any branch, we need to insert an OP_OPT item at the start of every +-following branch to ensure they get set correctly at run time, and also pass +-the new options into every subsequent branch compile. ++/* On entry, ptr is pointing past the bracket character, but on return it ++points to the closing bracket, or vertical bar, or end of string. The code ++variable is pointing at the byte into which the BRA operator has been stored. ++If the ims options are changed at the start (for a (?ims: group) or during any ++branch, we need to insert an OP_OPT item at the start of every following branch ++to ensure they get set correctly at run time, and also pass the new options ++into every subsequent branch compile. ++ ++This function is used during the pre-compile phase when we are trying to find ++out the amount of memory needed, as well as during the real compile phase. The ++value of lengthptr distinguishes the two phases. + + Argument: + options option bits, including any changes for this subpattern + oldims previous settings of ims option bits +- brackets -> int containing the number of extracting brackets used + codeptr -> the address of the current code pointer + ptrptr -> the address of the current pattern pointer + errorcodeptr -> pointer to error code variable + lookbehind TRUE if this is a lookbehind assertion +- skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER) ++ skipbytes skip this many bytes at start (for brackets and OP_COND) + firstbyteptr place to put the first required character, or a negative number + reqbyteptr place to put the last required character, or a negative number + bcptr pointer to the chain of currently open branches + cd points to the data block with tables pointers etc. ++ lengthptr NULL during the real compile phase ++ points to length accumulator during pre-compile phase + +-Returns: TRUE on success ++Returns: TRUE on success + */ + + static BOOL +-compile_regex(int options, int oldims, int *brackets, uschar **codeptr, +- const uschar **ptrptr, int *errorcodeptr, BOOL lookbehind, int skipbytes, +- int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd) ++compile_regex(int options, int oldims, uschar **codeptr, const uschar **ptrptr, ++ int *errorcodeptr, BOOL lookbehind, int skipbytes, int *firstbyteptr, ++ int *reqbyteptr, branch_chain *bcptr, compile_data *cd, int *lengthptr) + { + const uschar *ptr = *ptrptr; + uschar *code = *codeptr; +@@ -3595,6 +4593,7 @@ + uschar *reverse_count = NULL; + int firstbyte, reqbyte; + int branchfirstbyte, branchreqbyte; ++int length; + branch_chain bc; + + bc.outer = bcptr; +@@ -3602,6 +4601,20 @@ + + firstbyte = reqbyte = REQ_UNSET; + ++/* 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 ++beginning. We accumulate in a local variable to save frequent testing of ++lenthptr for NULL. We cannot do this by looking at the value of code at the ++start and end of each alternative, because compiled items are discarded during ++the pre-compile phase so that the work space is not exceeded. */ ++ ++length = 2 + 2*LINK_SIZE + skipbytes; ++ ++/* WARNING: If the above line is changed for any reason, you must also change ++the code that abstracts option settings at the start of the pattern and makes ++them global. It tests the value of length for (2 + 2*LINK_SIZE) in the ++pre-compile phase to find out whether anything has yet been compiled or not. */ ++ + /* Offset is set zero to mark that this bracket is still open */ + + PUT(code, 1, 0); +@@ -3617,6 +4630,7 @@ + { + *code++ = OP_OPT; + *code++ = options & PCRE_IMS; ++ length += 2; + } + + /* Set up dummy OP_REVERSE if lookbehind assertion */ +@@ -3626,73 +4640,80 @@ + *code++ = OP_REVERSE; + reverse_count = code; + PUTINC(code, 0, 0); ++ length += 1 + LINK_SIZE; + } + +- /* Now compile the branch */ ++ /* Now compile the branch; in the pre-compile phase its length gets added ++ into the length. */ + +- if (!compile_branch(&options, brackets, &code, &ptr, errorcodeptr, +- &branchfirstbyte, &branchreqbyte, &bc, cd)) ++ if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstbyte, ++ &branchreqbyte, &bc, cd, (lengthptr == NULL)? NULL : &length)) + { + *ptrptr = ptr; + return FALSE; + } + +- /* If this is the first branch, the firstbyte and reqbyte values for the +- branch become the values for the regex. */ ++ /* In the real compile phase, there is some post-processing to be done. */ + +- if (*last_branch != OP_ALT) ++ if (lengthptr == NULL) + { +- firstbyte = branchfirstbyte; +- reqbyte = branchreqbyte; +- } ++ /* If this is the first branch, the firstbyte and reqbyte values for the ++ branch become the values for the regex. */ + +- /* If this is not the first branch, the first char and reqbyte have to +- match the values from all the previous branches, except that if the previous +- value for reqbyte didn't have REQ_VARY set, it can still match, and we set +- REQ_VARY for the regex. */ ++ if (*last_branch != OP_ALT) ++ { ++ firstbyte = branchfirstbyte; ++ reqbyte = branchreqbyte; ++ } + +- else +- { +- /* If we previously had a firstbyte, but it doesn't match the new branch, +- we have to abandon the firstbyte for the regex, but if there was previously +- no reqbyte, it takes on the value of the old firstbyte. */ ++ /* If this is not the first branch, the first char and reqbyte have to ++ match the values from all the previous branches, except that if the ++ previous value for reqbyte didn't have REQ_VARY set, it can still match, ++ and we set REQ_VARY for the regex. */ + +- if (firstbyte >= 0 && firstbyte != branchfirstbyte) ++ else + { +- if (reqbyte < 0) reqbyte = firstbyte; +- firstbyte = REQ_NONE; +- } ++ /* If we previously had a firstbyte, but it doesn't match the new branch, ++ we have to abandon the firstbyte for the regex, but if there was ++ previously no reqbyte, it takes on the value of the old firstbyte. */ ++ ++ if (firstbyte >= 0 && firstbyte != branchfirstbyte) ++ { ++ if (reqbyte < 0) reqbyte = firstbyte; ++ firstbyte = REQ_NONE; ++ } + +- /* If we (now or from before) have no firstbyte, a firstbyte from the +- branch becomes a reqbyte if there isn't a branch reqbyte. */ ++ /* If we (now or from before) have no firstbyte, a firstbyte from the ++ branch becomes a reqbyte if there isn't a branch reqbyte. */ + +- if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) +- branchreqbyte = branchfirstbyte; ++ if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0) ++ branchreqbyte = branchfirstbyte; + +- /* Now ensure that the reqbytes match */ ++ /* Now ensure that the reqbytes match */ + +- if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) +- reqbyte = REQ_NONE; +- else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ +- } ++ if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY)) ++ reqbyte = REQ_NONE; ++ else reqbyte |= branchreqbyte; /* To "or" REQ_VARY */ ++ } + +- /* If lookbehind, check that this branch matches a fixed-length string, +- and put the length into the OP_REVERSE item. Temporarily mark the end of +- the branch with OP_END. */ ++ /* If lookbehind, check that this branch matches a fixed-length string, and ++ put the length into the OP_REVERSE item. Temporarily mark the end of the ++ branch with OP_END. */ + +- if (lookbehind) +- { +- int length; +- *code = OP_END; +- length = find_fixedlength(last_branch, options); +- DPRINTF(("fixed length = %d\n", length)); +- if (length < 0) ++ if (lookbehind) + { +- *errorcodeptr = (length == -2)? ERR36 : ERR25; +- *ptrptr = ptr; +- return FALSE; ++ int fixed_length; ++ *code = OP_END; ++ fixed_length = find_fixedlength(last_branch, options); ++ DPRINTF(("fixed length = %d\n", fixed_length)); ++ if (fixed_length < 0) ++ { ++ *errorcodeptr = (fixed_length == -2)? ERR36 : ERR25; ++ *ptrptr = ptr; ++ return FALSE; ++ } ++ PUT(reverse_count, 0, fixed_length); + } +- PUT(reverse_count, 0, length); + } + + /* Reached end of expression, either ')' or end of pattern. Go back through +@@ -3706,15 +4727,15 @@ + + if (*ptr != '|') + { +- int length = code - last_branch; ++ int branch_length = code - last_branch; + do + { + int prev_length = GET(last_branch, 1); +- PUT(last_branch, 1, length); +- length = prev_length; +- last_branch -= length; ++ PUT(last_branch, 1, branch_length); ++ branch_length = prev_length; ++ last_branch -= branch_length; + } +- while (length > 0); ++ while (branch_length > 0); + + /* Fill in the ket */ + +@@ -3728,6 +4749,7 @@ + { + *code++ = OP_OPT; + *code++ = oldims; ++ length += 2; + } + + /* Set values to pass back */ +@@ -3736,6 +4758,7 @@ + *ptrptr = ptr; + *firstbyteptr = firstbyte; + *reqbyteptr = reqbyte; ++ if (lengthptr != NULL) *lengthptr += length; + return TRUE; + } + +@@ -3749,6 +4772,7 @@ + bc.current = last_branch = code; + code += 1 + LINK_SIZE; + ptr++; ++ length += 1 + LINK_SIZE; + } + /* Control never reaches here */ + } +@@ -3799,24 +4823,29 @@ + unsigned int backref_map) + { + do { +- const uschar *scode = +- first_significant_code(code + 1+LINK_SIZE, options, PCRE_MULTILINE, FALSE); ++ const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], ++ options, PCRE_MULTILINE, FALSE); + register int op = *scode; + ++ /* Non-capturing brackets */ ++ ++ if (op == OP_BRA) ++ { ++ if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; ++ } ++ + /* Capturing brackets */ + +- if (op > OP_BRA) ++ else if (op == OP_CBRA) + { +- int new_map; +- op -= OP_BRA; +- if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); +- new_map = bracket_map | ((op < 32)? (1 << op) : 1); ++ int n = GET2(scode, 1+LINK_SIZE); ++ int new_map = bracket_map | ((n < 32)? (1 << n) : 1); + if (!is_anchored(scode, options, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + +- else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) ++ else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { + if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE; + } +@@ -3824,7 +4853,8 @@ + /* .* is not anchored unless DOTALL is set and it isn't in brackets that + are or may be referenced. */ + +- else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && ++ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || ++ op == OP_TYPEPOSSTAR) && + (*options & PCRE_DOTALL) != 0) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; +@@ -3869,30 +4899,35 @@ + unsigned int backref_map) + { + do { +- const uschar *scode = first_significant_code(code + 1+LINK_SIZE, NULL, 0, +- FALSE); ++ const uschar *scode = first_significant_code(code + _pcre_OP_lengths[*code], ++ NULL, 0, FALSE); + register int op = *scode; + ++ /* Non-capturing brackets */ ++ ++ if (op == OP_BRA) ++ { ++ if (!is_startline(scode, bracket_map, backref_map)) return FALSE; ++ } ++ + /* Capturing brackets */ + +- if (op > OP_BRA) ++ else if (op == OP_CBRA) + { +- int new_map; +- op -= OP_BRA; +- if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE); +- new_map = bracket_map | ((op < 32)? (1 << op) : 1); ++ int n = GET2(scode, 1+LINK_SIZE); ++ int new_map = bracket_map | ((n < 32)? (1 << n) : 1); + if (!is_startline(scode, new_map, backref_map)) return FALSE; + } + + /* Other brackets */ + +- else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) ++ else if (op == OP_ASSERT || op == OP_ONCE || op == OP_COND) + { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; } + + /* .* means "start at start or after \n" if it isn't in brackets that + may be referenced. */ + +- else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) ++ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) + { + if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE; + } +@@ -3941,14 +4976,13 @@ + first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS, TRUE); + register int op = *scode; + +- if (op >= OP_BRA) op = OP_BRA; +- + switch(op) + { + default: + return -1; + + case OP_BRA: ++ case OP_CBRA: + case OP_ASSERT: + case OP_ONCE: + case OP_COND: +@@ -3964,6 +4998,7 @@ + case OP_CHARNC: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + if (!inassert) return -1; + if (c < 0) + { +@@ -4012,37 +5047,36 @@ + } + + +- + PCRE_DATA_SCOPE pcre * + pcre_compile2(const char *pattern, int options, int *errorcodeptr, + const char **errorptr, int *erroroffset, const unsigned char *tables) + { + real_pcre *re; +-int length = 1 + LINK_SIZE; /* For initial BRA plus length */ +-int c, firstbyte, reqbyte, newline; +-int bracount = 0; +-int branch_extra = 0; +-int branch_newextra; +-int item_count = -1; +-int name_count = 0; +-int max_name_size = 0; +-int lastitemlength = 0; ++int length = 1; /* For final END opcode */ ++int firstbyte, reqbyte, newline; + int errorcode = 0; + #ifdef SUPPORT_UTF8 + BOOL utf8; +-BOOL class_utf8; + #endif +-BOOL inescq = FALSE; +-BOOL capturing; +-unsigned int brastackptr = 0; + size_t size; + uschar *code; + const uschar *codestart; + const uschar *ptr; + compile_data compile_block; + compile_data *cd = &compile_block; +-int brastack[BRASTACK_SIZE]; +-uschar bralenstack[BRASTACK_SIZE]; ++ ++/* This space is used for "compiling" into during the first phase, when we are ++computing the amount of memory that is needed. Compiled items are thrown away ++as soon as possible, so that a fairly large buffer should be sufficient for ++this purpose. The same space is used in the second phase for remembering where ++to fill in forward references to subpatterns. */ ++ ++uschar cworkspace[COMPILE_WORK_SIZE]; ++ ++ ++/* Set this early so that early errors get offset 0. */ ++ ++ptr = (const uschar *)pattern; + + /* We can't pass back an error message if errorptr is NULL; I guess the best we + can do is just return NULL, but we can set a code value if there is a code +@@ -4075,7 +5109,7 @@ + (*erroroffset = _pcre_valid_utf8((uschar *)pattern, -1)) >= 0) + { + errorcode = ERR44; +- goto PCRE_EARLY_ERROR_RETURN; ++ goto PCRE_UTF8_ERROR_RETURN; + } + #else + if ((options & PCRE_UTF8) != 0) +@@ -4099,34 +5133,43 @@ + cd->cbits = tables + cbits_offset; + cd->ctypes = tables + ctypes_offset; + +-/* Handle different types of newline. The two bits give four cases. The current +-code allows for one- or two-byte sequences. */ ++/* Handle different types of newline. The three bits give seven cases. The ++current code allows for fixed one- or two-byte sequences, plus "any". */ + +-switch (options & PCRE_NEWLINE_CRLF) ++switch (options & (PCRE_NEWLINE_CRLF | PCRE_NEWLINE_ANY)) + { +- default: newline = NEWLINE; break; /* Compile-time default */ ++ case 0: newline = NEWLINE; break; /* Compile-time default */ + case PCRE_NEWLINE_CR: newline = '\r'; break; + case PCRE_NEWLINE_LF: newline = '\n'; break; + case PCRE_NEWLINE_CR+ + PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; ++ case PCRE_NEWLINE_ANY: newline = -1; break; ++ default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; + } + +-if (newline > 255) ++if (newline < 0) + { +- cd->nllen = 2; +- cd->nl[0] = (newline >> 8) & 255; +- cd->nl[1] = newline & 255; ++ cd->nltype = NLTYPE_ANY; + } + else + { +- cd->nllen = 1; +- cd->nl[0] = newline; ++ cd->nltype = NLTYPE_FIXED; ++ if (newline > 255) ++ { ++ cd->nllen = 2; ++ cd->nl[0] = (newline >> 8) & 255; ++ cd->nl[1] = newline & 255; ++ } ++ else ++ { ++ cd->nllen = 1; ++ cd->nl[0] = newline; ++ } + } + +-/* Maximum back reference and backref bitmap. This is updated for numeric +-references during the first pass, but for named references during the actual +-compile pass. The bitmap records up to 31 back references to help in deciding +-whether (.*) can be treated as anchored or not. */ ++/* Maximum back reference and backref bitmap. The bitmap records up to 31 back ++references to help in deciding whether (.*) can be treated as anchored or not. ++*/ + + cd->top_backref = 0; + cd->backref_map = 0; +@@ -4136,1041 +5179,151 @@ + DPRINTF(("------------------------------------------------------------------\n")); + DPRINTF(("%s\n", pattern)); + +-/* The first thing to do is to make a pass over the pattern to compute the +-amount of store required to hold the compiled code. This does not have to be +-perfect as long as errors are overestimates. At the same time we can detect any +-flag settings right at the start, and extract them. Make an attempt to correct +-for any counted white space if an "extended" flag setting appears late in the +-pattern. We can't be so clever for #-comments. */ +- +-ptr = (const uschar *)(pattern - 1); +-while ((c = *(++ptr)) != 0) +- { +- int min, max; +- int class_optcount; +- int bracket_length; +- int duplength; ++/* Pretend to compile the pattern while actually just accumulating the length ++of memory required. This behaviour is triggered by passing a non-NULL final ++argument to compile_regex(). We pass a block of workspace (cworkspace) for it ++to compile parts of the pattern into; the compiled code is discarded when it is ++no longer needed, so hopefully this workspace will never overflow, though there ++is a test for its doing so. */ + +- /* If we are inside a \Q...\E sequence, all chars are literal */ ++cd->bracount = 0; ++cd->names_found = 0; ++cd->name_entry_size = 0; ++cd->name_table = NULL; ++cd->start_workspace = cworkspace; ++cd->start_code = cworkspace; ++cd->hwm = cworkspace; ++cd->start_pattern = (const uschar *)pattern; ++cd->end_pattern = (const uschar *)(pattern + strlen(pattern)); ++cd->req_varyopt = 0; ++cd->nopartial = FALSE; ++cd->external_options = options; + +- if (inescq) +- { +- if ((options & PCRE_AUTO_CALLOUT) != 0) length += 2 + 2*LINK_SIZE; +- goto NORMAL_CHAR; +- } ++/* Now do the pre-compile. On error, errorcode will be set non-zero, so we ++don't need to look at the result of the function here. The initial options have ++been put into the cd block so that they can be changed if an option setting is ++found within the regex right at the beginning. Bringing initial option settings ++outside can help speed up starting point checks. */ + +- /* Otherwise, first check for ignored whitespace and comments */ ++code = cworkspace; ++*code = OP_BRA; ++(void)compile_regex(cd->external_options, cd->external_options & PCRE_IMS, ++ &code, &ptr, &errorcode, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, &length); ++if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; + +- if ((options & PCRE_EXTENDED) != 0) +- { +- if ((cd->ctypes[c] & ctype_space) != 0) continue; +- if (c == '#') +- { +- while (*(++ptr) != 0) if (IS_NEWLINE(ptr)) break; +- if (*ptr != 0) +- { +- ptr += cd->nllen - 1; +- continue; +- } +- break; /* End loop at end of pattern */ +- } +- } ++DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, ++ cd->hwm - cworkspace)); + +- item_count++; /* Is zero for the first non-comment item */ ++if (length > MAX_PATTERN_SIZE) ++ { ++ errorcode = ERR20; ++ goto PCRE_EARLY_ERROR_RETURN; ++ } + +- /* Allow space for auto callout before every item except quantifiers. */ ++/* Compute the size of data block needed and get it, either from malloc or ++externally provided function. Integer overflow should no longer be possible ++because nowadays we limit the maximum value of cd->names_found and ++cd->name_entry_size. */ + +- if ((options & PCRE_AUTO_CALLOUT) != 0 && +- c != '*' && c != '+' && c != '?' && +- (c != '{' || !is_counted_repeat(ptr + 1))) +- length += 2 + 2*LINK_SIZE; ++size = length + sizeof(real_pcre) + cd->names_found * (cd->name_entry_size + 3); ++re = (real_pcre *)(pcre_malloc)(size); + +- switch(c) +- { +- /* A backslashed item may be an escaped data character or it may be a +- character type. */ ++if (re == NULL) ++ { ++ errorcode = ERR21; ++ goto PCRE_EARLY_ERROR_RETURN; ++ } + +- case '\\': +- c = check_escape(&ptr, &errorcode, bracount, options, FALSE); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; ++/* Put in the magic number, and save the sizes, initial options, and character ++table pointer. NULL is used for the default character tables. The nullpad field ++is at the end; it's there to help in the case when a regex compiled on a system ++with 4-byte pointers is run on another with 8-byte pointers. */ + +- lastitemlength = 1; /* Default length of last item for repeats */ ++re->magic_number = MAGIC_NUMBER; ++re->size = size; ++re->options = cd->external_options; ++re->dummy1 = 0; ++re->first_byte = 0; ++re->req_byte = 0; ++re->name_table_offset = sizeof(real_pcre); ++re->name_entry_size = cd->name_entry_size; ++re->name_count = cd->names_found; ++re->ref_count = 0; ++re->tables = (tables == _pcre_default_tables)? NULL : tables; ++re->nullpad = NULL; + +- if (c >= 0) /* Data character */ +- { +- length += 2; /* For a one-byte character */ ++/* 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 ++options are already set from the pre-compile phase, as is the name_entry_size ++field. Reset the bracket count and the names_found field. Also reset the hwm ++field; this time it's used for remembering forward references to subpatterns. ++*/ + +-#ifdef SUPPORT_UTF8 +- if (utf8 && c > 127) +- { +- int i; +- for (i = 0; i < _pcre_utf8_table1_size; i++) +- if (c <= _pcre_utf8_table1[i]) break; +- length += i; +- lastitemlength += i; +- } +-#endif ++cd->bracount = 0; ++cd->names_found = 0; ++cd->name_table = (uschar *)re + re->name_table_offset; ++codestart = cd->name_table + re->name_entry_size * re->name_count; ++cd->start_code = codestart; ++cd->hwm = cworkspace; ++cd->req_varyopt = 0; ++cd->nopartial = FALSE; + +- continue; +- } ++/* Set up a starting, non-extracting bracket, then compile the expression. On ++error, errorcode will be set non-zero, so we don't need to look at the result ++of the function here. */ + +- /* If \Q, enter "literal" mode */ ++ptr = (const uschar *)pattern; ++code = (uschar *)codestart; ++*code = OP_BRA; ++(void)compile_regex(re->options, re->options & PCRE_IMS, &code, &ptr, ++ &errorcode, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, NULL); ++re->top_bracket = cd->bracount; ++re->top_backref = cd->top_backref; + +- if (-c == ESC_Q) +- { +- inescq = TRUE; +- continue; +- } ++if (cd->nopartial) re->options |= PCRE_NOPARTIAL; + +- /* \X is supported only if Unicode property support is compiled */ ++/* If not reached end of pattern on success, there's an excess bracket. */ + +-#ifndef SUPPORT_UCP +- if (-c == ESC_X) +- { +- errorcode = ERR45; +- goto PCRE_ERROR_RETURN; +- } +-#endif ++if (errorcode == 0 && *ptr != 0) errorcode = ERR22; + +- /* \P and \p are for Unicode properties, but only when the support has +- been compiled. Each item needs 3 bytes. */ ++/* Fill in the terminating state and check for disastrous overflow, but ++if debugging, leave the test till after things are printed out. */ + +- else if (-c == ESC_P || -c == ESC_p) +- { +-#ifdef SUPPORT_UCP +- BOOL negated; +- BOOL pdata; +- length += 3; +- lastitemlength = 3; +- if (get_ucp(&ptr, &negated, &pdata, &errorcode) < 0) +- goto PCRE_ERROR_RETURN; +- continue; +-#else +- errorcode = ERR45; +- goto PCRE_ERROR_RETURN; ++*code++ = OP_END; ++ ++#ifndef DEBUG ++if (code - codestart > length) errorcode = ERR23; + #endif +- } + +- /* Other escapes need one byte */ ++/* Fill in any forward references that are required. */ + +- length++; ++while (errorcode == 0 && cd->hwm > cworkspace) ++ { ++ int offset, recno; ++ const uschar *groupptr; ++ cd->hwm -= LINK_SIZE; ++ offset = GET(cd->hwm, 0); ++ recno = GET(codestart, offset); ++ groupptr = find_bracket(codestart, (re->options & PCRE_UTF8) != 0, recno); ++ if (groupptr == NULL) errorcode = ERR53; ++ else PUT(((uschar *)codestart), offset, groupptr - codestart); ++ } + +- /* A back reference needs an additional 2 bytes, plus either one or 5 +- bytes for a repeat. We also need to keep the value of the highest +- back reference. */ ++/* Give an error if there's back reference to a non-existent capturing ++subpattern. */ + +- if (c <= -ESC_REF) +- { +- int refnum = -c - ESC_REF; +- cd->backref_map |= (refnum < 32)? (1 << refnum) : 1; +- if (refnum > cd->top_backref) +- cd->top_backref = refnum; +- length += 2; /* For single back reference */ +- if (ptr[1] == '{' && is_counted_repeat(ptr+2)) +- { +- ptr = read_repeat_counts(ptr+2, &min, &max, &errorcode); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- if ((min == 0 && (max == 1 || max == -1)) || +- (min == 1 && max == -1)) +- length++; +- else length += 5; +- if (ptr[1] == '?') ptr++; +- } +- } +- continue; +- +- case '^': /* Single-byte metacharacters */ +- case '.': +- case '$': +- length++; +- lastitemlength = 1; +- continue; +- +- case '*': /* These repeats won't be after brackets; */ +- case '+': /* those are handled separately */ +- case '?': +- length++; +- goto POSESSIVE; /* A few lines below */ +- +- /* This covers the cases of braced repeats after a single char, metachar, +- class, or back reference. */ +- +- case '{': +- if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR; +- ptr = read_repeat_counts(ptr+1, &min, &max, &errorcode); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- +- /* These special cases just insert one extra opcode */ +- +- if ((min == 0 && (max == 1 || max == -1)) || +- (min == 1 && max == -1)) +- length++; +- +- /* These cases might insert additional copies of a preceding character. */ +- +- else +- { +- if (min != 1) +- { +- length -= lastitemlength; /* Uncount the original char or metachar */ +- if (min > 0) length += 3 + lastitemlength; +- } +- length += lastitemlength + ((max > 0)? 3 : 1); +- } +- +- if (ptr[1] == '?') ptr++; /* Needs no extra length */ +- +- POSESSIVE: /* Test for possessive quantifier */ +- if (ptr[1] == '+') +- { +- ptr++; +- length += 2 + 2*LINK_SIZE; /* Allow for atomic brackets */ +- } +- continue; +- +- /* An alternation contains an offset to the next branch or ket. If any ims +- options changed in the previous branch(es), and/or if we are in a +- lookbehind assertion, extra space will be needed at the start of the +- branch. This is handled by branch_extra. */ +- +- case '|': +- length += 1 + LINK_SIZE + branch_extra; +- continue; +- +- /* A character class uses 33 characters provided that all the character +- values are less than 256. Otherwise, it uses a bit map for low valued +- characters, and individual items for others. Don't worry about character +- types that aren't allowed in classes - they'll get picked up during the +- compile. A character class that contains only one single-byte character +- uses 2 or 3 bytes, depending on whether it is negated or not. Notice this +- where we can. (In UTF-8 mode we can do this only for chars < 128.) */ +- +- case '[': +- if (*(++ptr) == '^') +- { +- class_optcount = 10; /* Greater than one */ +- ptr++; +- } +- else class_optcount = 0; +- +-#ifdef SUPPORT_UTF8 +- class_utf8 = FALSE; +-#endif +- +- /* Written as a "do" so that an initial ']' is taken as data */ +- +- if (*ptr != 0) do +- { +- /* Inside \Q...\E everything is literal except \E */ +- +- if (inescq) +- { +- if (*ptr != '\\' || ptr[1] != 'E') goto GET_ONE_CHARACTER; +- inescq = FALSE; +- ptr += 1; +- continue; +- } +- +- /* Outside \Q...\E, check for escapes */ +- +- if (*ptr == '\\') +- { +- c = check_escape(&ptr, &errorcode, bracount, options, TRUE); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- +- /* \b is backspace inside a class; \X is literal */ +- +- if (-c == ESC_b) c = '\b'; +- else if (-c == ESC_X) c = 'X'; +- +- /* \Q enters quoting mode */ +- +- else if (-c == ESC_Q) +- { +- inescq = TRUE; +- continue; +- } +- +- /* Handle escapes that turn into characters */ +- +- if (c >= 0) goto NON_SPECIAL_CHARACTER; +- +- /* Escapes that are meta-things. The normal ones just affect the +- bit map, but Unicode properties require an XCLASS extended item. */ +- +- else +- { +- class_optcount = 10; /* \d, \s etc; make sure > 1 */ +-#ifdef SUPPORT_UTF8 +- if (-c == ESC_p || -c == ESC_P) +- { +- if (!class_utf8) +- { +- class_utf8 = TRUE; +- length += LINK_SIZE + 2; +- } +- length += 3; +- } +-#endif +- } +- } +- +- /* Check the syntax for POSIX stuff. The bits we actually handle are +- checked during the real compile phase. */ +- +- else if (*ptr == '[' && +- (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && +- check_posix_syntax(ptr, &ptr, cd)) +- { +- ptr++; +- class_optcount = 10; /* Make sure > 1 */ +- } +- +- /* Anything else increments the possible optimization count. We have to +- detect ranges here so that we can compute the number of extra ranges for +- caseless wide characters when UCP support is available. If there are wide +- characters, we are going to have to use an XCLASS, even for single +- characters. */ +- +- else +- { +- int d; +- +- GET_ONE_CHARACTER: +- +-#ifdef SUPPORT_UTF8 +- if (utf8) +- { +- int extra = 0; +- GETCHARLEN(c, ptr, extra); +- ptr += extra; +- } +- else c = *ptr; +-#else +- c = *ptr; +-#endif +- +- /* Come here from handling \ above when it escapes to a char value */ +- +- NON_SPECIAL_CHARACTER: +- class_optcount++; +- +- d = -1; +- if (ptr[1] == '-') +- { +- uschar const *hyptr = ptr++; +- if (ptr[1] == '\\') +- { +- ptr++; +- d = check_escape(&ptr, &errorcode, bracount, options, TRUE); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- if (-d == ESC_b) d = '\b'; /* backspace */ +- else if (-d == ESC_X) d = 'X'; /* literal X in a class */ +- } +- else if (ptr[1] != 0 && ptr[1] != ']') +- { +- ptr++; +-#ifdef SUPPORT_UTF8 +- if (utf8) +- { +- int extra = 0; +- GETCHARLEN(d, ptr, extra); +- ptr += extra; +- } +- else +-#endif +- d = *ptr; +- } +- if (d < 0) ptr = hyptr; /* go back to hyphen as data */ +- } +- +- /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > +- 127 for caseless matching, we will need to use an XCLASS. */ +- +- if (d >= 0) +- { +- class_optcount = 10; /* Ensure > 1 */ +- if (d < c) +- { +- errorcode = ERR8; +- goto PCRE_ERROR_RETURN; +- } +- +-#ifdef SUPPORT_UTF8 +- if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127))) +- { +- uschar buffer[6]; +- if (!class_utf8) /* Allow for XCLASS overhead */ +- { +- class_utf8 = TRUE; +- length += LINK_SIZE + 2; +- } +- +-#ifdef SUPPORT_UCP +- /* If we have UCP support, find out how many extra ranges are +- needed to map the other case of characters within this range. We +- have to mimic the range optimization here, because extending the +- range upwards might push d over a boundary that makes is use +- another byte in the UTF-8 representation. */ +- +- if ((options & PCRE_CASELESS) != 0) +- { +- int occ, ocd; +- int cc = c; +- int origd = d; +- while (get_othercase_range(&cc, origd, &occ, &ocd)) +- { +- if (occ >= c && ocd <= d) continue; /* Skip embedded */ +- +- if (occ < c && ocd >= c - 1) /* Extend the basic range */ +- { /* if there is overlap, */ +- c = occ; /* noting that if occ < c */ +- continue; /* we can't have ocd > d */ +- } /* because a subrange is */ +- if (ocd > d && occ <= d + 1) /* always shorter than */ +- { /* the basic range. */ +- d = ocd; +- continue; +- } +- +- /* An extra item is needed */ +- +- length += 1 + _pcre_ord2utf8(occ, buffer) + +- ((occ == ocd)? 0 : _pcre_ord2utf8(ocd, buffer)); +- } +- } +-#endif /* SUPPORT_UCP */ +- +- /* The length of the (possibly extended) range */ +- +- length += 1 + _pcre_ord2utf8(c, buffer) + _pcre_ord2utf8(d, buffer); +- } +-#endif /* SUPPORT_UTF8 */ +- +- } +- +- /* We have a single character. There is nothing to be done unless we +- are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must +- allow for an XCL_SINGLE item, doubled for caselessness if there is UCP +- support. */ +- +- else +- { +-#ifdef SUPPORT_UTF8 +- if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127))) +- { +- uschar buffer[6]; +- class_optcount = 10; /* Ensure > 1 */ +- if (!class_utf8) /* Allow for XCLASS overhead */ +- { +- class_utf8 = TRUE; +- length += LINK_SIZE + 2; +- } +-#ifdef SUPPORT_UCP +- length += (((options & PCRE_CASELESS) != 0)? 2 : 1) * +- (1 + _pcre_ord2utf8(c, buffer)); +-#else /* SUPPORT_UCP */ +- length += 1 + _pcre_ord2utf8(c, buffer); +-#endif /* SUPPORT_UCP */ +- } +-#endif /* SUPPORT_UTF8 */ +- } +- } +- } +- while (*(++ptr) != 0 && (inescq || *ptr != ']')); /* Concludes "do" above */ +- +- if (*ptr == 0) /* Missing terminating ']' */ +- { +- errorcode = ERR6; +- goto PCRE_ERROR_RETURN; +- } +- +- /* We can optimize when there was only one optimizable character. Repeats +- for positive and negated single one-byte chars are handled by the general +- code. Here, we handle repeats for the class opcodes. */ +- +- if (class_optcount == 1) length += 3; else +- { +- length += 33; +- +- /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, +- we also need extra for wrapping the whole thing in a sub-pattern. */ +- +- if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2)) +- { +- ptr = read_repeat_counts(ptr+2, &min, &max, &errorcode); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- if ((min == 0 && (max == 1 || max == -1)) || +- (min == 1 && max == -1)) +- length++; +- else length += 5; +- if (ptr[1] == '+') +- { +- ptr++; +- length += 2 + 2*LINK_SIZE; +- } +- else if (ptr[1] == '?') ptr++; +- } +- } +- continue; +- +- /* Brackets may be genuine groups or special things */ +- +- case '(': +- branch_newextra = 0; +- bracket_length = 1 + LINK_SIZE; +- capturing = FALSE; +- +- /* Handle special forms of bracket, which all start (? */ +- +- if (ptr[1] == '?') +- { +- int set, unset; +- int *optset; +- +- switch (c = ptr[2]) +- { +- /* Skip over comments entirely */ +- case '#': +- ptr += 3; +- while (*ptr != 0 && *ptr != ')') ptr++; +- if (*ptr == 0) +- { +- errorcode = ERR18; +- goto PCRE_ERROR_RETURN; +- } +- continue; +- +- /* Non-referencing groups and lookaheads just move the pointer on, and +- then behave like a non-special bracket, except that they don't increment +- the count of extracting brackets. Ditto for the "once only" bracket, +- which is in Perl from version 5.005. */ +- +- case ':': +- case '=': +- case '!': +- case '>': +- ptr += 2; +- break; +- +- /* Named subpatterns are an extension copied from Python */ +- +- case 'P': +- ptr += 3; +- +- /* Handle the definition of a named subpattern */ +- +- if (*ptr == '<') +- { +- const uschar *p; /* Don't amalgamate; some compilers */ +- p = ++ptr; /* grumble at autoincrement in declaration */ +- while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; +- if (*ptr != '>') +- { +- errorcode = ERR42; +- goto PCRE_ERROR_RETURN; +- } +- name_count++; +- if (name_count > MAX_NAME_COUNT) +- { +- errorcode = ERR49; +- goto PCRE_ERROR_RETURN; +- } +- if (ptr - p > max_name_size) +- { +- max_name_size = (ptr - p); +- if (max_name_size > MAX_NAME_SIZE) +- { +- errorcode = ERR48; +- goto PCRE_ERROR_RETURN; +- } +- } +- capturing = TRUE; /* Named parentheses are always capturing */ +- break; /* Go handle capturing parentheses */ +- } +- +- /* Handle back references and recursive calls to named subpatterns */ +- +- if (*ptr == '=' || *ptr == '>') +- { +- length += 3 + 3*LINK_SIZE; /* Allow for the automatic "once" */ +- while ((cd->ctypes[*(++ptr)] & ctype_word) != 0); +- if (*ptr != ')') +- { +- errorcode = ERR42; +- goto PCRE_ERROR_RETURN; +- } +- goto RECURSE_CHECK_QUANTIFIED; +- } +- +- /* Unknown character after (?P */ +- +- errorcode = ERR41; +- goto PCRE_ERROR_RETURN; +- +- /* (?R) specifies a recursive call to the regex, which is an extension +- to provide the facility which can be obtained by (?p{perl-code}) in +- Perl 5.6. In Perl 5.8 this has become (??{perl-code}). +- +- From PCRE 4.00, items such as (?3) specify subroutine-like "calls" to +- the appropriate numbered brackets. This includes both recursive and +- non-recursive calls. (?R) is now synonymous with (?0). */ +- +- case 'R': +- ptr++; +- +- case '0': case '1': case '2': case '3': case '4': +- case '5': case '6': case '7': case '8': case '9': +- ptr += 2; +- if (c != 'R') +- while ((digitab[*(++ptr)] & ctype_digit) != 0); +- if (*ptr != ')') +- { +- errorcode = ERR29; +- goto PCRE_ERROR_RETURN; +- } +- length += 3 + 3*LINK_SIZE; /* Allows for the automatic "once" */ +- +- /* If this item is quantified, it will get wrapped inside brackets so +- as to use the code for quantified brackets. We jump down and use the +- code that handles this for real brackets. Come here from code for +- named recursions/subroutines. */ +- +- RECURSE_CHECK_QUANTIFIED: +- if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{') +- { +- length += 2 + 2 * LINK_SIZE; /* to make bracketed */ +- duplength = 5 + 3 * LINK_SIZE; +- goto HANDLE_QUANTIFIED_BRACKETS; +- } +- continue; +- +- /* (?C) is an extension which provides "callout" - to provide a bit of +- the functionality of the Perl (?{...}) feature. An optional number may +- follow (default is zero). */ +- +- case 'C': +- ptr += 2; +- while ((digitab[*(++ptr)] & ctype_digit) != 0); +- if (*ptr != ')') +- { +- errorcode = ERR39; +- goto PCRE_ERROR_RETURN; +- } +- length += 2 + 2*LINK_SIZE; +- continue; +- +- /* Lookbehinds are in Perl from version 5.005 */ +- +- case '<': +- ptr += 3; +- if (*ptr == '=' || *ptr == '!') +- { +- branch_newextra = 1 + LINK_SIZE; +- length += 1 + LINK_SIZE; /* For the first branch */ +- break; +- } +- errorcode = ERR24; +- goto PCRE_ERROR_RETURN; +- +- /* Conditionals are in Perl from version 5.005. The bracket must either +- be followed by a number (for bracket reference) or by an assertion +- group. PCRE extends this by allowing a name to reference a named group; +- unfortunately, previously 'R' was implemented for a recursion test. +- When this is compiled, we look for the named group 'R' first. At this +- point we just do a basic syntax check. */ +- +- case '(': +- if ((cd->ctypes[ptr[3]] & ctype_word) != 0) +- { +- ptr += 4; +- length += 3; +- while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++; +- if (*ptr != ')') +- { +- errorcode = ERR26; +- goto PCRE_ERROR_RETURN; +- } +- } +- else /* An assertion must follow */ +- { +- ptr++; /* Can treat like ':' as far as spacing is concerned */ +- if (ptr[2] != '?' || +- (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) +- { +- ptr += 2; /* To get right offset in message */ +- errorcode = ERR28; +- goto PCRE_ERROR_RETURN; +- } +- } +- break; +- +- /* Else loop checking valid options until ) is met. Anything else is an +- error. If we are without any brackets, i.e. at top level, the settings +- act as if specified in the options, so massage the options immediately. +- This is for backward compatibility with Perl 5.004. */ +- +- default: +- set = unset = 0; +- optset = &set; +- ptr += 2; +- +- for (;; ptr++) +- { +- c = *ptr; +- switch (c) +- { +- case 'i': +- *optset |= PCRE_CASELESS; +- continue; +- +- case 'J': +- *optset |= PCRE_DUPNAMES; +- options |= PCRE_JCHANGED; /* Record that it changed */ +- continue; +- +- case 'm': +- *optset |= PCRE_MULTILINE; +- continue; +- +- case 's': +- *optset |= PCRE_DOTALL; +- continue; +- +- case 'x': +- *optset |= PCRE_EXTENDED; +- continue; +- +- case 'X': +- *optset |= PCRE_EXTRA; +- continue; +- +- case 'U': +- *optset |= PCRE_UNGREEDY; +- continue; +- +- case '-': +- optset = &unset; +- continue; +- +- /* A termination by ')' indicates an options-setting-only item; if +- this is at the very start of the pattern (indicated by item_count +- being zero), we use it to set the global options. This is helpful +- when analyzing the pattern for first characters, etc. Otherwise +- nothing is done here and it is handled during the compiling +- process. +- +- We allow for more than one options setting at the start. If such +- settings do not change the existing options, nothing is compiled. +- However, we must leave space just in case something is compiled. +- This can happen for pathological sequences such as (?i)(?-i) +- because the global options will end up with -i set. The space is +- small and not significant. (Before I did this there was a reported +- bug with (?i)(?-i) in a machine-generated pattern.) +- +- [Historical note: Up to Perl 5.8, options settings at top level +- were always global settings, wherever they appeared in the pattern. +- That is, they were equivalent to an external setting. From 5.8 +- onwards, they apply only to what follows (which is what you might +- expect).] */ +- +- case ')': +- if (item_count == 0) +- { +- options = (options | set) & (~unset); +- set = unset = 0; /* To save length */ +- item_count--; /* To allow for several */ +- length += 2; +- } +- +- /* Fall through */ +- +- /* A termination by ':' indicates the start of a nested group with +- the given options set. This is again handled at compile time, but +- we must allow for compiled space if any of the ims options are +- set. We also have to allow for resetting space at the end of +- the group, which is why 4 is added to the length and not just 2. +- If there are several changes of options within the same group, this +- will lead to an over-estimate on the length, but this shouldn't +- matter very much. We also have to allow for resetting options at +- the start of any alternations, which we do by setting +- branch_newextra to 2. */ +- +- case ':': +- if (((set|unset) & PCRE_IMS) != 0) +- { +- length += 4; +- branch_newextra = 2; +- } +- goto END_OPTIONS; +- +- /* Unrecognized option character */ +- +- default: +- errorcode = ERR12; +- goto PCRE_ERROR_RETURN; +- } +- } +- +- /* If we hit a closing bracket, that's it - this is a freestanding +- option-setting. We need to ensure that branch_extra is updated if +- necessary. The only values branch_newextra can have here are 0 or 2. +- If the value is 2, then branch_extra must either be 2 or 5, depending +- on whether this is a lookbehind group or not. */ +- +- END_OPTIONS: +- if (c == ')') +- { +- if (branch_newextra == 2 && +- (branch_extra == 0 || branch_extra == 1+LINK_SIZE)) +- branch_extra += branch_newextra; +- continue; +- } +- +- /* If options were terminated by ':' control comes here. This is a +- non-capturing group with an options change. There is nothing more that +- needs to be done because "capturing" is already set FALSE by default; +- we can just fall through. */ +- +- } +- } +- +- /* Ordinary parentheses, not followed by '?', are capturing unless +- PCRE_NO_AUTO_CAPTURE is set. */ +- +- else capturing = (options & PCRE_NO_AUTO_CAPTURE) == 0; +- +- /* Capturing brackets must be counted so we can process escapes in a +- Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need +- an additional 3 bytes of memory per capturing bracket. */ +- +- if (capturing) +- { +- bracount++; +- if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3; +- } +- +- /* Save length for computing whole length at end if there's a repeat that +- requires duplication of the group. Also save the current value of +- branch_extra, and start the new group with the new value. If non-zero, this +- will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ +- +- if (brastackptr >= sizeof(brastack)/sizeof(int)) +- { +- errorcode = ERR19; +- goto PCRE_ERROR_RETURN; +- } +- +- bralenstack[brastackptr] = branch_extra; +- branch_extra = branch_newextra; +- +- brastack[brastackptr++] = length; +- length += bracket_length; +- continue; +- +- /* Handle ket. Look for subsequent max/min; for certain sets of values we +- have to replicate this bracket up to that many times. If brastackptr is +- 0 this is an unmatched bracket which will generate an error, but take care +- not to try to access brastack[-1] when computing the length and restoring +- the branch_extra value. */ +- +- case ')': +- length += 1 + LINK_SIZE; +- if (brastackptr > 0) +- { +- duplength = length - brastack[--brastackptr]; +- branch_extra = bralenstack[brastackptr]; +- /* This is a paranoid check to stop integer overflow later on */ +- if (duplength > MAX_DUPLENGTH) +- { +- errorcode = ERR50; +- goto PCRE_ERROR_RETURN; +- } +- } +- else duplength = 0; +- +- /* The following code is also used when a recursion such as (?3) is +- followed by a quantifier, because in that case, it has to be wrapped inside +- brackets so that the quantifier works. The value of duplength must be +- set before arrival. */ +- +- HANDLE_QUANTIFIED_BRACKETS: +- +- /* Leave ptr at the final char; for read_repeat_counts this happens +- automatically; for the others we need an increment. */ +- +- if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2)) +- { +- ptr = read_repeat_counts(ptr+2, &min, &max, &errorcode); +- if (errorcode != 0) goto PCRE_ERROR_RETURN; +- } +- else if (c == '*') { min = 0; max = -1; ptr++; } +- else if (c == '+') { min = 1; max = -1; ptr++; } +- else if (c == '?') { min = 0; max = 1; ptr++; } +- else { min = 1; max = 1; } +- +- /* If the minimum is zero, we have to allow for an OP_BRAZERO before the +- group, and if the maximum is greater than zero, we have to replicate +- maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting +- bracket set. */ +- +- if (min == 0) +- { +- length++; +- if (max > 0) length += (max - 1) * (duplength + 3 + 2*LINK_SIZE); +- } +- +- /* When the minimum is greater than zero, we have to replicate up to +- minval-1 times, with no additions required in the copies. Then, if there +- is a limited maximum we have to replicate up to maxval-1 times allowing +- for a BRAZERO item before each optional copy and nesting brackets for all +- but one of the optional copies. */ +- +- else +- { +- length += (min - 1) * duplength; +- if (max > min) /* Need this test as max=-1 means no limit */ +- length += (max - min) * (duplength + 3 + 2*LINK_SIZE) +- - (2 + 2*LINK_SIZE); +- } +- +- /* Allow space for once brackets for "possessive quantifier" */ +- +- if (ptr[1] == '+') +- { +- ptr++; +- length += 2 + 2*LINK_SIZE; +- } +- continue; +- +- /* Non-special character. It won't be space or # in extended mode, so it is +- always a genuine character. If we are in a \Q...\E sequence, check for the +- end; if not, we have a literal. */ +- +- default: +- NORMAL_CHAR: +- +- if (inescq && c == '\\' && ptr[1] == 'E') +- { +- inescq = FALSE; +- ptr++; +- continue; +- } +- +- length += 2; /* For a one-byte character */ +- lastitemlength = 1; /* Default length of last item for repeats */ +- +- /* In UTF-8 mode, check for additional bytes. */ +- +-#ifdef SUPPORT_UTF8 +- if (utf8 && (c & 0xc0) == 0xc0) +- { +- while ((ptr[1] & 0xc0) == 0x80) /* Can't flow over the end */ +- { /* because the end is marked */ +- lastitemlength++; /* by a zero byte. */ +- length++; +- ptr++; +- } +- } +-#endif +- +- continue; +- } +- } +- +-length += 2 + LINK_SIZE; /* For final KET and END */ +- +-if ((options & PCRE_AUTO_CALLOUT) != 0) +- length += 2 + 2*LINK_SIZE; /* For final callout */ +- +-if (length > MAX_PATTERN_SIZE) +- { +- errorcode = ERR20; +- goto PCRE_EARLY_ERROR_RETURN; +- } +- +-/* Compute the size of data block needed and get it, either from malloc or +-externally provided function. Integer overflow should no longer be possible +-because nowadays we limit the maximum value of name_count and max_name size. */ +- +-size = length + sizeof(real_pcre) + name_count * (max_name_size + 3); +-re = (real_pcre *)(pcre_malloc)(size); +- +-if (re == NULL) +- { +- errorcode = ERR21; +- goto PCRE_EARLY_ERROR_RETURN; +- } +- +-/* Put in the magic number, and save the sizes, options, and character table +-pointer. NULL is used for the default character tables. The nullpad field is at +-the end; it's there to help in the case when a regex compiled on a system with +-4-byte pointers is run on another with 8-byte pointers. */ +- +-re->magic_number = MAGIC_NUMBER; +-re->size = size; +-re->options = options; +-re->dummy1 = 0; +-re->name_table_offset = sizeof(real_pcre); +-re->name_entry_size = max_name_size + 3; +-re->name_count = name_count; +-re->ref_count = 0; +-re->tables = (tables == _pcre_default_tables)? NULL : tables; +-re->nullpad = NULL; +- +-/* The starting points of the name/number translation table and of the code are +-passed around in the compile data block. */ +- +-cd->names_found = 0; +-cd->name_entry_size = max_name_size + 3; +-cd->name_table = (uschar *)re + re->name_table_offset; +-codestart = cd->name_table + re->name_entry_size * re->name_count; +-cd->start_code = codestart; +-cd->start_pattern = (const uschar *)pattern; +-cd->req_varyopt = 0; +-cd->nopartial = FALSE; +- +-/* Set up a starting, non-extracting bracket, then compile the expression. On +-error, errorcode will be set non-zero, so we don't need to look at the result +-of the function here. */ +- +-ptr = (const uschar *)pattern; +-code = (uschar *)codestart; +-*code = OP_BRA; +-bracount = 0; +-(void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr, +- &errorcode, FALSE, 0, &firstbyte, &reqbyte, NULL, cd); +-re->top_bracket = bracount; +-re->top_backref = cd->top_backref; +- +-if (cd->nopartial) re->options |= PCRE_NOPARTIAL; +- +-/* If not reached end of pattern on success, there's an excess bracket. */ +- +-if (errorcode == 0 && *ptr != 0) errorcode = ERR22; +- +-/* Fill in the terminating state and check for disastrous overflow, but +-if debugging, leave the test till after things are printed out. */ +- +-*code++ = OP_END; +- +-#ifndef DEBUG +-if (code - codestart > length) errorcode = ERR23; +-#endif +- +-/* Give an error if there's back reference to a non-existent capturing +-subpattern. */ +- +-if (re->top_backref > re->top_bracket) errorcode = ERR15; ++if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15; + + /* Failed to compile, or error while post-processing */ + + if (errorcode != 0) + { + (pcre_free)(re); +- PCRE_ERROR_RETURN: +- *erroroffset = ptr - (const uschar *)pattern; + PCRE_EARLY_ERROR_RETURN: ++ *erroroffset = ptr - (const uschar *)pattern; ++#ifdef SUPPORT_UTF8 ++ PCRE_UTF8_ERROR_RETURN: ++#endif + *errorptr = error_texts[errorcode]; + if (errorcodeptr != NULL) *errorcodeptr = errorcode; + return NULL; +@@ -5180,15 +5333,15 @@ + the pattern is anchored by virtue of ^ characters or \A or anything else (such + as starting with .* when DOTALL is set). + +-Otherwise, if we know what the first character 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 + 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. + */ + +-if ((options & PCRE_ANCHORED) == 0) ++if ((re->options & PCRE_ANCHORED) == 0) + { +- int temp_options = options; ++ int temp_options = re->options; /* May get changed during these scans */ + if (is_anchored(codestart, &temp_options, 0, cd->backref_map)) + re->options |= PCRE_ANCHORED; + else +@@ -5273,7 +5426,7 @@ + if (errorcodeptr != NULL) *errorcodeptr = ERR23; + return NULL; + } +-#endif ++#endif /* DEBUG */ + + return (pcre *)re; + } +diff -ruN ../pcre.orig/pcrelib/pcre_exec.c ./pcrelib/pcre_exec.c +--- ../pcre.orig/pcrelib/pcre_exec.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_exec.c Fri Feb 9 22:31:19 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -42,25 +42,22 @@ + pattern matching using an NFA algorithm, trying to mimic Perl as closely as + possible. There are also some static supporting functions. */ + +-#define NLBLOCK md /* The block containing newline information */ ++#define NLBLOCK md /* Block containing newline information */ ++#define PSSTART start_subject /* Field containing processed string start */ ++#define PSEND end_subject /* Field containing processed string end */ ++ + #include "pcre_internal.h" + ++/* The chain of eptrblocks for tail recursions uses memory in stack workspace, ++obtained at top level, the size of which is defined by EPTR_WORK_SIZE. */ + +-/* Structure for building a chain of data that actually lives on the +-stack, for holding the values of the subject pointer at the start of each +-subpattern, so as to detect when an empty string has been matched by a +-subpattern - to break infinite loops. When NO_RECURSE is set, these blocks +-are on the heap, not on the stack. */ +- +-typedef struct eptrblock { +- struct eptrblock *epb_prev; +- USPTR epb_saved_eptr; +-} eptrblock; ++#define EPTR_WORK_SIZE (1000) + + /* Flag bits for the match() function */ + +-#define match_condassert 0x01 /* Called to check a condition assertion */ +-#define match_isgroup 0x02 /* Set if start of bracketed group */ ++#define match_condassert 0x01 /* Called to check a condition assertion */ ++#define match_cbegroup 0x02 /* Could-be-empty unlimited repeat group */ ++#define match_tail_recursed 0x04 /* Tail recursive call */ + + /* Non-error returns from the match() function. Error returns are externally + defined PCRE_ERROR_xxx codes, which are all negative. */ +@@ -101,7 +98,7 @@ + static void + pchars(const uschar *p, int length, BOOL is_subject, match_data *md) + { +-int c; ++unsigned int c; + if (is_subject && length > md->end_subject - p) length = md->end_subject - p; + while (length-- > 0) + if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); +@@ -291,7 +288,6 @@ + + BOOL Xcur_is_word; + BOOL Xcondition; +- BOOL Xminimize; + BOOL Xprev_is_word; + + unsigned long int Xoriginal_ims; +@@ -303,11 +299,10 @@ + int Xprop_category; + int Xprop_chartype; + int Xprop_script; +- int *Xprop_test_variable; + #endif + + int Xctype; +- int Xfc; ++ unsigned int Xfc; + int Xfi; + int Xlength; + int Xmax; +@@ -340,10 +335,7 @@ + * Match from current position * + *************************************************/ + +-/* On entry ecode points to the first opcode, and eptr to the first character +-in the subject string, while eptrb holds the value of eptr at the start of the +-last bracketed group - used for breaking infinite loops matching zero-length +-strings. This function is called recursively in many circumstances. Whenever it ++/* This function is called recursively in many circumstances. Whenever it + returns a negative (error) response, the outer incarnation must also return the + same response. + +@@ -353,8 +345,8 @@ + made performance worse. + + Arguments: +- eptr pointer in subject +- ecode position in code ++ eptr pointer to current character in subject ++ ecode pointer to current position in compiled code + offset_top current top pointer + md pointer to "static" info for the match + ims current /i, /m, and /s options +@@ -362,7 +354,9 @@ + brackets - for testing for empty matches + flags can contain + match_condassert - this is an assertion condition +- match_isgroup - this is the start of a bracketed group ++ match_cbegroup - this is the start of an unlimited repeat ++ group that can match an empty string ++ match_tail_recursed - this is a tail_recursed group + rdepth the recursion depth + + Returns: MATCH_MATCH if matched ) these values are >= 0 +@@ -377,14 +371,16 @@ + int flags, unsigned int rdepth) + { + /* These variables do not need to be preserved over recursion in this function, +-so they can be ordinary variables in all cases. Mark them with "register" +-because they are used a lot in loops. */ ++so they can be ordinary variables in all cases. Mark some of them with ++"register" because they are used a lot in loops. */ + + register int rrc; /* Returns from recursive calls */ + register int i; /* Used for loops not involving calls to RMATCH() */ +-register unsigned int c; /* Character values not kept over RMATCH() calls */ ++register unsigned int c; /* Character values not kept over RMATCH() calls */ + register BOOL utf8; /* Local copy of UTF-8 flag for speed */ + ++BOOL minimize, possessive; /* Quantifier options */ ++ + /* When recursion is not being used, all "local" variables that have to be + preserved over calls to RMATCH() are part of a "frame" which is obtained from + heap storage. Set up the top-level frame here; others are obtained from the +@@ -434,7 +430,6 @@ + + #define cur_is_word frame->Xcur_is_word + #define condition frame->Xcondition +-#define minimize frame->Xminimize + #define prev_is_word frame->Xprev_is_word + + #define original_ims frame->Xoriginal_ims +@@ -446,7 +441,6 @@ + #define prop_category frame->Xprop_category + #define prop_chartype frame->Xprop_chartype + #define prop_script frame->Xprop_script +-#define prop_test_variable frame->Xprop_test_variable + #endif + + #define ctype frame->Xctype +@@ -470,7 +464,7 @@ + get preserved during recursion in the normal way. In this environment, fi and + i, and fc and c, can be the same variables. */ + +-#else ++#else /* NO_RECURSE not defined */ + #define fi i + #define fc c + +@@ -489,7 +483,6 @@ + /* that do not have to be preserved over */ + BOOL cur_is_word; /* a recursive call to RMATCH(). */ + BOOL condition; +-BOOL minimize; + BOOL prev_is_word; + + unsigned long int original_ims; +@@ -501,7 +494,6 @@ + int prop_category; + int prop_chartype; + int prop_script; +-int *prop_test_variable; + #endif + + int ctype; +@@ -516,7 +508,7 @@ + int stacksave[REC_STACK_SAVE_MAX]; + + eptrblock newptrb; +-#endif ++#endif /* NO_RECURSE */ + + /* These statements are here to stop the compiler complaining about unitialized + variables. */ +@@ -524,9 +516,9 @@ + #ifdef SUPPORT_UCP + prop_value = 0; + prop_fail_result = 0; +-prop_test_variable = NULL; + #endif + ++ + /* This label is used for tail recursion, which is used in a few cases even + when NO_RECURSE is not defined, in order to reduce the amount of stack that is + used. Thanks to Ian Taylor for noticing this possibility and sending the +@@ -556,24 +548,34 @@ + utf8 = FALSE; + #endif + +-/* At the start of a bracketed group, add the current subject pointer to the +-stack of such pointers, to be re-instated at the end of the group when we hit +-the closing ket. When match() is called in other circumstances, we don't add to +-this stack. */ ++/* At the start of a group with an unlimited repeat that may match an empty ++string, the match_cbegroup flag is set. When this is the case, add the current ++subject pointer to the chain of such remembered pointers, to be checked when we ++hit the closing ket, in order to break infinite loops that match no characters. ++When match() is called in other circumstances, don't add to the chain. If this ++is a tail recursion, use a block from the workspace, as the one on the stack is ++already used. */ + +-if ((flags & match_isgroup) != 0) ++if ((flags & match_cbegroup) != 0) + { +- newptrb.epb_prev = eptrb; +- newptrb.epb_saved_eptr = eptr; +- eptrb = &newptrb; ++ eptrblock *p; ++ if ((flags & match_tail_recursed) != 0) ++ { ++ if (md->eptrn >= EPTR_WORK_SIZE) RRETURN(PCRE_ERROR_NULLWSLIMIT); ++ p = md->eptrchain + md->eptrn++; ++ } ++ else p = &newptrb; ++ p->epb_saved_eptr = eptr; ++ p->epb_prev = eptrb; ++ eptrb = p; + } + +-/* Now start processing the operations. */ ++/* Now start processing the opcodes. */ + + for (;;) + { ++ minimize = possessive = FALSE; + op = *ecode; +- minimize = FALSE; + + /* For partial matching, remember if we ever hit the end of the subject after + matching at least one subject character. */ +@@ -583,33 +585,30 @@ + eptr > md->start_match) + md->hitend = TRUE; + +- /* Opening capturing bracket. If there is space in the offset vector, save +- the current subject position in the working slot at the top of the vector. We +- mustn't change the current values of the data slot, because they may be set +- from a previous iteration of this group, and be referred to by a reference +- inside the group. +- +- If the bracket fails to match, we need to restore this value and also the +- values of the final offsets, in case they were set by a previous iteration of +- the same bracket. +- +- If there isn't enough space in the offset vector, treat this as if it were a +- non-capturing bracket. Don't worry about setting the flag for the error case +- here; that is handled in the code for KET. */ +- +- if (op > OP_BRA) ++ switch(op) + { +- number = op - OP_BRA; +- +- /* For extended extraction brackets (large number), we have to fish out the +- number from a dummy opcode at the start. */ +- +- if (number > EXTRACT_BASIC_MAX) +- number = GET2(ecode, 2+LINK_SIZE); ++ /* Handle a capturing bracket. If there is space in the offset vector, save ++ the current subject position in the working slot at the top of the vector. ++ We mustn't change the current values of the data slot, because they may be ++ set from a previous iteration of this group, and be referred to by a ++ reference inside the group. ++ ++ If the bracket fails to match, we need to restore this value and also the ++ values of the final offsets, in case they were set by a previous iteration ++ of the same bracket. ++ ++ If there isn't enough space in the offset vector, treat this as if it were ++ a non-capturing bracket. Don't worry about setting the flag for the error ++ case here; that is handled in the code for KET. */ ++ ++ case OP_CBRA: ++ case OP_SCBRA: ++ number = GET2(ecode, 1+LINK_SIZE); + offset = number << 1; + + #ifdef DEBUG +- printf("start bracket %d subject=", number); ++ printf("start bracket %d\n", number); ++ printf("subject="); + pchars(eptr, 16, TRUE, md); + printf("\n"); + #endif +@@ -624,10 +623,11 @@ + DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); + md->offset_vector[md->offset_end - number] = eptr - md->start_subject; + ++ flags = (op == OP_SCBRA)? match_cbegroup : 0; + do + { +- RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, +- match_isgroup); ++ RMATCH(rrc, eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ++ ims, eptrb, flags); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + md->capture_last = save_capture_last; + ecode += GET(ecode, 1); +@@ -643,39 +643,35 @@ + RRETURN(MATCH_NOMATCH); + } + +- /* Insufficient room for saving captured contents */ +- +- else op = OP_BRA; +- } +- +- /* Other types of node can be handled by a switch */ ++ /* Insufficient room for saving captured contents. Treat as a non-capturing ++ bracket. */ + +- switch(op) +- { +- case OP_BRA: /* Non-capturing bracket: optimized */ +- DPRINTF(("start bracket 0\n")); +- +- /* Loop for all the alternatives */ ++ DPRINTF(("insufficient capture room: treat as non-capturing\n")); + ++ /* Non-capturing bracket. Loop for all the alternatives. When we get to the ++ final alternative within the brackets, we would return the result of a ++ recursive call to match() whatever happened. We can reduce stack usage by ++ turning this into a tail recursion. */ ++ ++ case OP_BRA: ++ case OP_SBRA: ++ DPRINTF(("start non-capturing bracket\n")); ++ flags = (op >= OP_SBRA)? match_cbegroup : 0; + for (;;) + { +- /* When we get to the final alternative within the brackets, we would +- return the result of a recursive call to match() whatever happened. We +- can reduce stack usage by turning this into a tail recursion. */ +- + if (ecode[GET(ecode, 1)] != OP_ALT) +- { +- ecode += 1 + LINK_SIZE; +- flags = match_isgroup; +- DPRINTF(("bracket 0 tail recursion\n")); +- goto TAIL_RECURSE; +- } ++ { ++ ecode += _pcre_OP_lengths[*ecode]; ++ flags |= match_tail_recursed; ++ DPRINTF(("bracket 0 tail recursion\n")); ++ goto TAIL_RECURSE; ++ } + + /* For non-final alternatives, continue the loop for a NOMATCH result; + otherwise return. */ + +- RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, +- match_isgroup); ++ RMATCH(rrc, eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, ++ eptrb, flags); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += GET(ecode, 1); + } +@@ -688,54 +684,72 @@ + obeyed, we can use tail recursion to avoid using another stack frame. */ + + case OP_COND: +- if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */ ++ case OP_SCOND: ++ if (ecode[LINK_SIZE+1] == OP_RREF) /* Recursion test */ ++ { ++ offset = GET2(ecode, LINK_SIZE + 2); /* Recursion group number*/ ++ condition = md->recursive != NULL && ++ (offset == RREF_ANY || offset == md->recursive->group_num); ++ ecode += condition? 3 : GET(ecode, 1); ++ } ++ ++ else if (ecode[LINK_SIZE+1] == OP_CREF) /* Group used test */ + { + offset = GET2(ecode, LINK_SIZE+2) << 1; /* Doubled ref number */ +- condition = (offset == CREF_RECURSE * 2)? +- (md->recursive != NULL) : +- (offset < offset_top && md->offset_vector[offset] >= 0); +- ecode += condition? (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1)); +- flags = match_isgroup; +- goto TAIL_RECURSE; ++ condition = offset < offset_top && md->offset_vector[offset] >= 0; ++ ecode += condition? 3 : GET(ecode, 1); ++ } ++ ++ else if (ecode[LINK_SIZE+1] == OP_DEF) /* DEFINE - always false */ ++ { ++ condition = FALSE; ++ ecode += GET(ecode, 1); + } + + /* The condition is an assertion. Call match() to evaluate it - setting +- the final argument TRUE causes it to stop at the end of an assertion. */ ++ the final argument match_condassert causes it to stop at the end of an ++ assertion. */ + + else + { + RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, +- match_condassert | match_isgroup); ++ match_condassert); + if (rrc == MATCH_MATCH) + { +- ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE+2); ++ condition = TRUE; ++ ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE + 2); + while (*ecode == OP_ALT) ecode += GET(ecode, 1); + } + else if (rrc != MATCH_NOMATCH) + { + RRETURN(rrc); /* Need braces because of following else */ + } +- else ecode += GET(ecode, 1); ++ else ++ { ++ condition = FALSE; ++ ecode += GET(ecode, 1); ++ } ++ } + +- /* We are now at the branch that is to be obeyed. As there is only one, +- we can use tail recursion to avoid using another stack frame. */ ++ /* We are now at the branch that is to be obeyed. As there is only one, ++ we can use tail recursion to avoid using another stack frame. If the second ++ alternative doesn't exist, we can just plough on. */ + ++ if (condition || *ecode == OP_ALT) ++ { + ecode += 1 + LINK_SIZE; +- flags = match_isgroup; ++ flags = match_tail_recursed | ((op == OP_SCOND)? match_cbegroup : 0); + goto TAIL_RECURSE; + } +- /* Control never reaches here */ +- +- /* Skip over conditional reference or large extraction number data if +- encountered. */ +- +- case OP_CREF: +- case OP_BRANUMBER: +- ecode += 3; ++ else ++ { ++ ecode += 1 + LINK_SIZE; ++ } + break; + +- /* End of the pattern. If we are in a recursion, we should restore the +- offsets appropriately and continue from after the call. */ ++ ++ /* End of the pattern. If we are in a top-level recursion, we should ++ restore the offsets appropriately and continue from after the call. */ + + case OP_END: + if (md->recursive != NULL && md->recursive->group_num == 0) +@@ -777,8 +791,7 @@ + case OP_ASSERTBACK: + do + { +- RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, +- match_isgroup); ++ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0); + if (rrc == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += GET(ecode, 1); +@@ -804,8 +817,7 @@ + case OP_ASSERTBACK_NOT: + do + { +- RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, +- match_isgroup); ++ RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0); + if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += GET(ecode,1); +@@ -826,8 +838,8 @@ + #ifdef SUPPORT_UTF8 + if (utf8) + { +- c = GET(ecode,1); +- for (i = 0; i < c; i++) ++ i = GET(ecode, 1); ++ while (i-- > 0) + { + eptr--; + if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); +@@ -840,7 +852,7 @@ + /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ + + { +- eptr -= GET(ecode,1); ++ eptr -= GET(ecode, 1); + if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); + } + +@@ -897,13 +909,8 @@ + case OP_RECURSE: + { + callpat = md->start_code + GET(ecode, 1); +- new_recursive.group_num = *callpat - OP_BRA; +- +- /* For extended extraction brackets (large number), we have to fish out +- the number from a dummy opcode at the start. */ +- +- if (new_recursive.group_num > EXTRACT_BASIC_MAX) +- new_recursive.group_num = GET2(callpat, 2+LINK_SIZE); ++ new_recursive.group_num = (callpat == md->start_code)? 0 : ++ GET2(callpat, 1 + LINK_SIZE); + + /* Add to "recursing stack" */ + +@@ -936,10 +943,11 @@ + restore the offset and recursion data. */ + + DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); ++ flags = (*callpat >= OP_SBRA)? match_cbegroup : 0; + do + { +- RMATCH(rrc, eptr, callpat + 1 + LINK_SIZE, offset_top, md, ims, +- eptrb, match_isgroup); ++ RMATCH(rrc, eptr, callpat + _pcre_OP_lengths[*callpat], offset_top, ++ md, ims, eptrb, flags); + if (rrc == MATCH_MATCH) + { + DPRINTF(("Recursion matched\n")); +@@ -983,7 +991,7 @@ + do + { + RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, +- eptrb, match_isgroup); ++ eptrb, 0); + if (rrc == MATCH_MATCH) break; + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += GET(ecode,1); +@@ -997,7 +1005,7 @@ + /* Continue as from after the assertion, updating the offsets high water + mark, since extracts may have been taken. */ + +- do ecode += GET(ecode,1); while (*ecode == OP_ALT); ++ do ecode += GET(ecode, 1); while (*ecode == OP_ALT); + + offset_top = md->end_offset_top; + eptr = md->end_match_ptr; +@@ -1031,15 +1039,15 @@ + RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode = prev; +- flags = match_isgroup; ++ flags = match_tail_recursed; + goto TAIL_RECURSE; + } + else /* OP_KETRMAX */ + { +- RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); ++ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_cbegroup); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += 1 + LINK_SIZE; +- flags = 0; ++ flags = match_tail_recursed; + goto TAIL_RECURSE; + } + /* Control never gets here */ +@@ -1060,38 +1068,44 @@ + case OP_BRAZERO: + { + next = ecode+1; +- RMATCH(rrc, eptr, next, offset_top, md, ims, eptrb, match_isgroup); ++ RMATCH(rrc, eptr, next, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + do next += GET(next,1); while (*next == OP_ALT); +- ecode = next + 1+LINK_SIZE; ++ ecode = next + 1 + LINK_SIZE; + } + break; + + case OP_BRAMINZERO: + { + next = ecode+1; +- do next += GET(next,1); while (*next == OP_ALT); +- RMATCH(rrc, eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, +- match_isgroup); ++ do next += GET(next, 1); while (*next == OP_ALT); ++ RMATCH(rrc, eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode++; + } + break; + +- /* End of a group, repeated or non-repeating. If we are at the end of +- an assertion "group", stop matching and return MATCH_MATCH, but record the +- current high water mark for use by positive assertions. Do this also +- for the "once" (not-backup up) groups. */ ++ /* End of a group, repeated or non-repeating. */ + + case OP_KET: + case OP_KETRMIN: + case OP_KETRMAX: + prev = ecode - GET(ecode, 1); +- saved_eptr = eptrb->epb_saved_eptr; + +- /* Back up the stack of bracket start pointers. */ ++ /* If this was a group that remembered the subject start, in order to break ++ infinite repeats of empty string matches, retrieve the subject start from ++ the chain. Otherwise, set it NULL. */ ++ ++ if (*prev >= OP_SBRA) ++ { ++ saved_eptr = eptrb->epb_saved_eptr; /* Value at start of group */ ++ eptrb = eptrb->epb_prev; /* Backup to previous group */ ++ } ++ else saved_eptr = NULL; + +- eptrb = eptrb->epb_prev; ++ /* If we are at the end of an assertion group, stop matching and return ++ MATCH_MATCH, but record the current high water mark for use by positive ++ assertions. Do this also for the "once" (atomic) groups. */ + + if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || + *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || +@@ -1102,18 +1116,15 @@ + RRETURN(MATCH_MATCH); + } + +- /* In all other cases except a conditional group we have to check the +- group number back at the start and if necessary complete handling an +- extraction by setting the offsets and bumping the high water mark. */ ++ /* For capturing groups we have to check the group number back at the start ++ and if necessary complete handling an extraction by setting the offsets and ++ bumping the high water mark. Note that whole-pattern recursion is coded as ++ a recurse into group 0, so it won't be picked up here. Instead, we catch it ++ when the OP_END is reached. Other recursion is handled here. */ + +- if (*prev != OP_COND) ++ if (*prev == OP_CBRA || *prev == OP_SCBRA) + { +- number = *prev - OP_BRA; +- +- /* For extended extraction brackets (large number), we have to fish out +- the number from a dummy opcode at the start. */ +- +- if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE); ++ number = GET2(prev, 1+LINK_SIZE); + offset = number << 1; + + #ifdef DEBUG +@@ -1121,42 +1132,34 @@ + printf("\n"); + #endif + +- /* Test for a numbered group. This includes groups called as a result +- of recursion. Note that whole-pattern recursion is coded as a recurse +- into group 0, so it won't be picked up here. Instead, we catch it when +- the OP_END is reached. */ +- +- if (number > 0) ++ md->capture_last = number; ++ if (offset >= md->offset_max) md->offset_overflow = TRUE; else + { +- md->capture_last = number; +- if (offset >= md->offset_max) md->offset_overflow = TRUE; else +- { +- md->offset_vector[offset] = +- md->offset_vector[md->offset_end - number]; +- md->offset_vector[offset+1] = eptr - md->start_subject; +- if (offset_top <= offset) offset_top = offset + 2; +- } +- +- /* Handle a recursively called group. Restore the offsets +- appropriately and continue from after the call. */ +- +- if (md->recursive != NULL && md->recursive->group_num == number) +- { +- recursion_info *rec = md->recursive; +- DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); +- md->recursive = rec->prevrec; +- md->start_match = rec->save_start; +- memcpy(md->offset_vector, rec->offset_save, +- rec->saved_max * sizeof(int)); +- ecode = rec->after_call; +- ims = original_ims; +- break; +- } ++ md->offset_vector[offset] = ++ md->offset_vector[md->offset_end - number]; ++ md->offset_vector[offset+1] = eptr - md->start_subject; ++ if (offset_top <= offset) offset_top = offset + 2; ++ } ++ ++ /* Handle a recursively called group. Restore the offsets ++ appropriately and continue from after the call. */ ++ ++ if (md->recursive != NULL && md->recursive->group_num == number) ++ { ++ recursion_info *rec = md->recursive; ++ DPRINTF(("Recursion (%d) succeeded - continuing\n", number)); ++ md->recursive = rec->prevrec; ++ md->start_match = rec->save_start; ++ memcpy(md->offset_vector, rec->offset_save, ++ rec->saved_max * sizeof(int)); ++ ecode = rec->after_call; ++ ims = original_ims; ++ break; + } + } + +- /* Reset the value of the ims flags, in case they got changed during +- the group. */ ++ /* For both capturing and non-capturing groups, reset the value of the ims ++ flags, in case they got changed during the group. */ + + ims = original_ims; + DPRINTF(("ims reset to %02lx\n", ims)); +@@ -1177,20 +1180,22 @@ + preceding bracket, in the appropriate order. In the second case, we can use + tail recursion to avoid using another stack frame. */ + ++ flags = (*prev >= OP_SBRA)? match_cbegroup : 0; ++ + if (*ecode == OP_KETRMIN) + { + RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode = prev; +- flags = match_isgroup; ++ flags |= match_tail_recursed; + goto TAIL_RECURSE; + } + else /* OP_KETRMAX */ + { +- RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup); ++ RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, flags); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + ecode += 1 + LINK_SIZE; +- flags = 0; ++ flags = match_tail_recursed; + goto TAIL_RECURSE; + } + /* Control never gets here */ +@@ -1202,9 +1207,7 @@ + if ((ims & PCRE_MULTILINE) != 0) + { + if (eptr != md->start_subject && +- (eptr == md->end_subject || +- eptr < md->start_subject + md->nllen || +- !IS_NEWLINE(eptr - md->nllen))) ++ (eptr == md->end_subject || !WAS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + ecode++; + break; +@@ -1244,7 +1247,7 @@ + if (!md->endonly) + { + if (eptr != md->end_subject && +- (eptr != md->end_subject - md->nllen || !IS_NEWLINE(eptr))) ++ (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) + RRETURN(MATCH_NOMATCH); + ecode++; + break; +@@ -1263,7 +1266,7 @@ + + case OP_EODN: + if (eptr != md->end_subject && +- (eptr != md->end_subject - md->nllen || !IS_NEWLINE(eptr))) ++ (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) + RRETURN(MATCH_NOMATCH); + ecode++; + break; +@@ -1319,8 +1322,7 @@ + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0) + { +- if (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)) +- RRETURN(MATCH_NOMATCH); ++ if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); + } + if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH); + if (utf8) +@@ -1414,6 +1416,26 @@ + ecode++; + break; + ++ case OP_ANYNL: ++ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); ++ GETCHARINCTEST(c, eptr); ++ switch(c) ++ { ++ default: RRETURN(MATCH_NOMATCH); ++ case 0x000d: ++ if (eptr < md->end_subject && *eptr == 0x0a) eptr++; ++ break; ++ case 0x000a: ++ case 0x000b: ++ case 0x000c: ++ case 0x0085: ++ case 0x2028: ++ case 0x2029: ++ break; ++ } ++ ecode++; ++ break; ++ + #ifdef SUPPORT_UCP + /* Check the next character by Unicode property. We will get here only + if the support is in the binary; otherwise a compile-time error occurs. */ +@@ -1456,7 +1478,6 @@ + + default: + RRETURN(PCRE_ERROR_INTERNAL); +- break; + } + + ecode += 3; +@@ -1926,7 +1947,7 @@ + + else + { +- int dc; ++ unsigned int dc; + GETCHARINC(dc, eptr); + ecode += length; + +@@ -1953,13 +1974,17 @@ + } + break; + +- /* Match a single character repeatedly; different opcodes share code. */ ++ /* Match a single character repeatedly. */ + + case OP_EXACT: + min = max = GET2(ecode, 1); + ecode += 3; + goto REPEATCHAR; + ++ case OP_POSUPTO: ++ possessive = TRUE; ++ /* Fall through */ ++ + case OP_UPTO: + case OP_MINUPTO: + min = 0; +@@ -1968,6 +1993,27 @@ + ecode += 3; + goto REPEATCHAR; + ++ case OP_POSSTAR: ++ possessive = TRUE; ++ min = 0; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATCHAR; ++ ++ case OP_POSPLUS: ++ possessive = TRUE; ++ min = 1; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATCHAR; ++ ++ case OP_POSQUERY: ++ possessive = TRUE; ++ min = 0; ++ max = 1; ++ ecode++; ++ goto REPEATCHAR; ++ + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: +@@ -2003,10 +2049,9 @@ + uschar occhars[8]; + + #ifdef SUPPORT_UCP +- int othercase; ++ unsigned int othercase; + if ((ims & PCRE_CASELESS) != 0 && +- (othercase = _pcre_ucp_othercase(fc)) >= 0 && +- othercase >= 0) ++ (othercase = _pcre_ucp_othercase(fc)) != NOTACHAR) + oclength = _pcre_ord2utf8(othercase, occhars); + #endif /* SUPPORT_UCP */ + +@@ -2042,7 +2087,8 @@ + } + /* Control never gets here */ + } +- else ++ ++ else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) +@@ -2056,6 +2102,8 @@ + eptr += oclength; + } + } ++ ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2110,7 +2158,7 @@ + } + /* Control never gets here */ + } +- else ++ else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) +@@ -2118,6 +2166,7 @@ + if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break; + eptr++; + } ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2146,7 +2195,7 @@ + } + /* Control never gets here */ + } +- else ++ else /* Maximize */ + { + pp = eptr; + for (i = min; i < max; i++) +@@ -2154,6 +2203,7 @@ + if (eptr >= md->end_subject || fc != *eptr) break; + eptr++; + } ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2206,6 +2256,34 @@ + ecode += 3; + goto REPEATNOTCHAR; + ++ case OP_NOTPOSSTAR: ++ possessive = TRUE; ++ min = 0; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATNOTCHAR; ++ ++ case OP_NOTPOSPLUS: ++ possessive = TRUE; ++ min = 1; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATNOTCHAR; ++ ++ case OP_NOTPOSQUERY: ++ possessive = TRUE; ++ min = 0; ++ max = 1; ++ ecode++; ++ goto REPEATNOTCHAR; ++ ++ case OP_NOTPOSUPTO: ++ possessive = TRUE; ++ min = 0; ++ max = GET2(ecode, 1); ++ ecode += 3; ++ goto REPEATNOTCHAR; ++ + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: +@@ -2245,7 +2323,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); +@@ -2270,7 +2348,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (fi = min;; fi++) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2306,7 +2384,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (i = min; i < max; i++) + { + int len = 1; +@@ -2316,7 +2394,8 @@ + if (fc == d) break; + eptr += len; + } +- for(;;) ++ if (possessive) continue; ++ for(;;) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); +@@ -2333,6 +2412,7 @@ + if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break; + eptr++; + } ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2354,7 +2434,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (i = 1; i <= min; i++) + { + GETCHARINC(d, eptr); +@@ -2377,7 +2457,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (fi = min;; fi++) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2412,7 +2492,7 @@ + /* UTF-8 mode */ + if (utf8) + { +- register int d; ++ register unsigned int d; + for (i = min; i < max; i++) + { + int len = 1; +@@ -2421,6 +2501,7 @@ + if (fc == d) break; + eptr += len; + } ++ if (possessive) continue; + for(;;) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2438,6 +2519,7 @@ + if (eptr >= md->end_subject || fc == *eptr) break; + eptr++; + } ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -2469,6 +2551,34 @@ + ecode += 3; + goto REPEATTYPE; + ++ case OP_TYPEPOSSTAR: ++ possessive = TRUE; ++ min = 0; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATTYPE; ++ ++ case OP_TYPEPOSPLUS: ++ possessive = TRUE; ++ min = 1; ++ max = INT_MAX; ++ ecode++; ++ goto REPEATTYPE; ++ ++ case OP_TYPEPOSQUERY: ++ possessive = TRUE; ++ min = 0; ++ max = 1; ++ ecode++; ++ goto REPEATTYPE; ++ ++ case OP_TYPEPOSUPTO: ++ possessive = TRUE; ++ min = 0; ++ max = GET2(ecode, 1); ++ ecode += 3; ++ goto REPEATTYPE; ++ + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: +@@ -2571,7 +2681,6 @@ + + default: + RRETURN(PCRE_ERROR_INTERNAL); +- break; + } + } + +@@ -2611,9 +2720,7 @@ + for (i = 1; i <= min; i++) + { + if (eptr >= md->end_subject || +- ((ims & PCRE_DOTALL) == 0 && +- eptr <= md->end_subject - md->nllen && +- IS_NEWLINE(eptr))) ++ ((ims & PCRE_DOTALL) == 0 && IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; +@@ -2624,6 +2731,28 @@ + eptr += min; + break; + ++ case OP_ANYNL: ++ for (i = 1; i <= min; i++) ++ { ++ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); ++ GETCHARINC(c, eptr); ++ switch(c) ++ { ++ default: RRETURN(MATCH_NOMATCH); ++ case 0x000d: ++ if (eptr < md->end_subject && *eptr == 0x0a) eptr++; ++ break; ++ case 0x000a: ++ case 0x000b: ++ case 0x000c: ++ case 0x0085: ++ case 0x2028: ++ case 0x2029: ++ break; ++ } ++ } ++ break; ++ + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + { +@@ -2692,7 +2821,8 @@ + #endif /* SUPPORT_UTF8 */ + + /* Code for the non-UTF-8 case for minimum matching of operators other +- than OP_PROP and OP_NOTPROP. */ ++ than OP_PROP and OP_NOTPROP. We can assume that there are the minimum ++ number of bytes present, as this was tested above. */ + + switch(ctype) + { +@@ -2701,8 +2831,7 @@ + { + for (i = 1; i <= min; i++) + { +- if (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)) +- RRETURN(MATCH_NOMATCH); ++ if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); + eptr++; + } + } +@@ -2713,6 +2842,28 @@ + eptr += min; + break; + ++ /* Because of the CRLF case, we can't assume the minimum number of ++ bytes are present in this case. */ ++ ++ case OP_ANYNL: ++ for (i = 1; i <= min; i++) ++ { ++ if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH); ++ switch(*eptr++) ++ { ++ default: RRETURN(MATCH_NOMATCH); ++ case 0x000d: ++ if (eptr < md->end_subject && *eptr == 0x0a) eptr++; ++ break; ++ case 0x000a: ++ case 0x000b: ++ case 0x000c: ++ case 0x0085: ++ break; ++ } ++ } ++ break; ++ + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); +@@ -2774,7 +2925,7 @@ + GETCHARINC(c, eptr); + if (prop_fail_result) RRETURN(MATCH_NOMATCH); + } +- break; ++ /* Control never gets here */ + + case PT_LAMP: + for (fi = min;; fi++) +@@ -2789,7 +2940,7 @@ + prop_chartype == ucp_Lt) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } +- break; ++ /* Control never gets here */ + + case PT_GC: + for (fi = min;; fi++) +@@ -2802,7 +2953,7 @@ + if ((prop_category == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } +- break; ++ /* Control never gets here */ + + case PT_PC: + for (fi = min;; fi++) +@@ -2815,7 +2966,7 @@ + if ((prop_chartype == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } +- break; ++ /* Control never gets here */ + + case PT_SC: + for (fi = min;; fi++) +@@ -2828,11 +2979,10 @@ + if ((prop_script == prop_value) == prop_fail_result) + RRETURN(MATCH_NOMATCH); + } +- break; ++ /* Control never gets here */ + + default: + RRETURN(PCRE_ERROR_INTERNAL); +- break; + } + } + +@@ -2876,7 +3026,7 @@ + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || + (ctype == OP_ANY && (ims & PCRE_DOTALL) == 0 && +- eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))) ++ IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + + GETCHARINC(c, eptr); +@@ -2888,6 +3038,23 @@ + case OP_ANYBYTE: + break; + ++ case OP_ANYNL: ++ switch(c) ++ { ++ default: RRETURN(MATCH_NOMATCH); ++ case 0x000d: ++ if (eptr < md->end_subject && *eptr == 0x0a) eptr++; ++ break; ++ case 0x000a: ++ case 0x000b: ++ case 0x000c: ++ case 0x0085: ++ case 0x2028: ++ case 0x2029: ++ break; ++ } ++ break; ++ + case OP_NOT_DIGIT: + if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) + RRETURN(MATCH_NOMATCH); +@@ -2932,8 +3099,7 @@ + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (fi >= max || eptr >= md->end_subject || +- ((ims & PCRE_DOTALL) == 0 && +- eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))) ++ ((ims & PCRE_DOTALL) == 0 && IS_NEWLINE(eptr))) + RRETURN(MATCH_NOMATCH); + + c = *eptr++; +@@ -2945,6 +3111,21 @@ + case OP_ANYBYTE: + break; + ++ case OP_ANYNL: ++ switch(c) ++ { ++ default: RRETURN(MATCH_NOMATCH); ++ case 0x000d: ++ if (eptr < md->end_subject && *eptr == 0x0a) eptr++; ++ break; ++ case 0x000a: ++ case 0x000b: ++ case 0x000c: ++ case 0x0085: ++ break; ++ } ++ break; ++ + case OP_NOT_DIGIT: + if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); + break; +@@ -2977,7 +3158,7 @@ + /* Control never gets here */ + } + +- /* If maximizing it is worth using inline code for speed, doing the type ++ /* If maximizing, it is worth using inline code for speed, doing the type + test once at the start (i.e. keep it out of the loop). Again, keep the + UTF-8 and UCP stuff separate. */ + +@@ -3058,6 +3239,7 @@ + + /* eptr is now past the end of the maximum run */ + ++ if (possessive) continue; + for(;;) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -3093,6 +3275,7 @@ + + /* eptr is now past the end of the maximum run */ + ++ if (possessive) continue; + for(;;) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -3135,9 +3318,7 @@ + { + for (i = min; i < max; i++) + { +- if (eptr >= md->end_subject || +- (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))) +- break; ++ if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + } +@@ -3161,9 +3342,7 @@ + { + for (i = min; i < max; i++) + { +- if (eptr >= md->end_subject || +- (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))) +- break; ++ if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + } + break; +@@ -3171,7 +3350,8 @@ + else + { + c = max - min; +- if (c > md->end_subject - eptr) c = md->end_subject - eptr; ++ if (c > (unsigned int)(md->end_subject - eptr)) ++ c = md->end_subject - eptr; + eptr += c; + } + } +@@ -3181,10 +3361,32 @@ + + case OP_ANYBYTE: + c = max - min; +- if (c > md->end_subject - eptr) c = md->end_subject - eptr; ++ if (c > (unsigned int)(md->end_subject - eptr)) ++ c = md->end_subject - eptr; + eptr += c; + break; + ++ case OP_ANYNL: ++ for (i = min; i < max; i++) ++ { ++ int len = 1; ++ if (eptr >= md->end_subject) break; ++ GETCHARLEN(c, eptr, len); ++ if (c == 0x000d) ++ { ++ if (++eptr >= md->end_subject) break; ++ if (*eptr == 0x000a) eptr++; ++ } ++ else ++ { ++ if (c != 0x000a && c != 0x000b && c != 0x000c && ++ c != 0x0085 && c != 0x2028 && c != 0x2029) ++ break; ++ eptr += len; ++ } ++ } ++ break; ++ + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { +@@ -3257,6 +3459,7 @@ + + /* eptr is now past the end of the maximum run */ + ++ if (possessive) continue; + for(;;) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -3277,9 +3480,7 @@ + { + for (i = min; i < max; i++) + { +- if (eptr >= md->end_subject || +- (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))) +- break; ++ if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; + eptr++; + } + break; +@@ -3288,10 +3489,30 @@ + + case OP_ANYBYTE: + c = max - min; +- if (c > md->end_subject - eptr) c = md->end_subject - eptr; ++ if (c > (unsigned int)(md->end_subject - eptr)) ++ c = md->end_subject - eptr; + eptr += c; + break; + ++ case OP_ANYNL: ++ for (i = min; i < max; i++) ++ { ++ if (eptr >= md->end_subject) break; ++ c = *eptr; ++ if (c == 0x000d) ++ { ++ if (++eptr >= md->end_subject) break; ++ if (*eptr == 0x000a) eptr++; ++ } ++ else ++ { ++ if (c != 0x000a && c != 0x000b && c != 0x000c && c != 0x0085) ++ break; ++ eptr++; ++ } ++ } ++ break; ++ + case OP_NOT_DIGIT: + for (i = min; i < max; i++) + { +@@ -3352,6 +3573,7 @@ + + /* eptr is now past the end of the maximum run */ + ++ if (possessive) continue; + while (eptr >= pp) + { + RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0); +@@ -3366,14 +3588,12 @@ + } + /* Control never gets here */ + +- /* There's been some horrible disaster. Since all codes > OP_BRA are +- for capturing brackets, and there shouldn't be any gaps between 0 and +- OP_BRA, arrival here can only mean there is something seriously wrong +- in the code above or the OP_xxx definitions. */ ++ /* There's been some horrible disaster. Arrival here can only mean there is ++ something seriously wrong in the code above or the OP_xxx definitions. */ + + default: + DPRINTF(("Unknown opcode %d\n", *ecode)); +- RRETURN(PCRE_ERROR_UNKNOWN_NODE); ++ RRETURN(PCRE_ERROR_UNKNOWN_OPCODE); + } + + /* Do not stick any code in here without much thought; it is assumed +@@ -3411,7 +3631,6 @@ + + #undef cur_is_word + #undef condition +-#undef minimize + #undef prev_is_word + + #undef original_ims +@@ -3484,6 +3703,7 @@ + BOOL firstline; + BOOL first_byte_caseless = FALSE; + BOOL req_byte_caseless = FALSE; ++BOOL utf8; + match_data match_block; + match_data *md = &match_block; + const uschar *tables; +@@ -3491,6 +3711,7 @@ + USPTR start_match = (USPTR)subject + start_offset; + USPTR end_subject; + USPTR req_byte_ptr = start_match - 1; ++eptrblock eptrchain[EPTR_WORK_SIZE]; + + pcre_study_data internal_study; + const pcre_study_data *study; +@@ -3567,7 +3788,7 @@ + end_subject = md->end_subject; + + md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; +-md->utf8 = (re->options & PCRE_UTF8) != 0; ++utf8 = md->utf8 = (re->options & PCRE_UTF8) != 0; + + md->notbol = (options & PCRE_NOTBOL) != 0; + md->noteol = (options & PCRE_NOTEOL) != 0; +@@ -3576,6 +3797,7 @@ + md->hitend = FALSE; + + md->recursive = NULL; /* No recursion at top level */ ++md->eptrchain = eptrchain; /* Make workspace generally available */ + + md->lcc = tables + lcc_offset; + md->ctypes = tables + ctypes_offset; +@@ -3583,26 +3805,36 @@ + /* Handle different types of newline. The two bits give four cases. If nothing + is set at run time, whatever was used at compile time applies. */ + +-switch ((((options & PCRE_NEWLINE_CRLF) == 0)? re->options : options) & +- PCRE_NEWLINE_CRLF) ++switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : options) & ++ PCRE_NEWLINE_BITS) + { +- default: newline = NEWLINE; break; /* Compile-time default */ ++ case 0: newline = NEWLINE; break; /* Compile-time default */ + case PCRE_NEWLINE_CR: newline = '\r'; break; + case PCRE_NEWLINE_LF: newline = '\n'; break; + case PCRE_NEWLINE_CR+ + PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break; ++ case PCRE_NEWLINE_ANY: newline = -1; break; ++ default: return PCRE_ERROR_BADNEWLINE; + } + +-if (newline > 255) ++if (newline < 0) + { +- md->nllen = 2; +- md->nl[0] = (newline >> 8) & 255; +- md->nl[1] = newline & 255; ++ md->nltype = NLTYPE_ANY; + } + else + { +- md->nllen = 1; +- md->nl[0] = newline; ++ md->nltype = NLTYPE_FIXED; ++ if (newline > 255) ++ { ++ md->nllen = 2; ++ md->nl[0] = (newline >> 8) & 255; ++ md->nl[1] = newline & 255; ++ } ++ else ++ { ++ md->nllen = 1; ++ md->nl[0] = newline; ++ } + } + + /* Partial matching is supported only for a restricted set of regexes at the +@@ -3615,7 +3847,7 @@ + back the character offset. */ + + #ifdef SUPPORT_UTF8 +-if (md->utf8 && (options & PCRE_NO_UTF8_CHECK) == 0) ++if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0) + { + if (_pcre_valid_utf8((uschar *)subject, length) >= 0) + return PCRE_ERROR_BADUTF8; +@@ -3707,10 +3939,13 @@ + req_byte2 = (tables + fcc_offset)[req_byte]; /* case flipped */ + } + ++ ++/* ==========================================================================*/ ++ + /* Loop for handling unanchored repeated matching attempts; for anchored regexs + the loop runs just once. */ + +-do ++for(;;) + { + USPTR save_end_subject = end_subject; + +@@ -3725,14 +3960,14 @@ + + /* Advance to a unique first char if possible. If firstline is TRUE, the + start of the match is constrained to the first line of a multiline string. +- Implement this by temporarily adjusting end_subject so that we stop scanning +- at a newline. If the match fails at the newline, later code breaks this loop. +- */ ++ That is, the match must be before or at the first newline. Implement this by ++ temporarily adjusting end_subject so that we stop scanning at a newline. If ++ the match fails at the newline, later code breaks this loop. */ + + if (firstline) + { + USPTR t = start_match; +- while (t <= save_end_subject - md->nllen && !IS_NEWLINE(t)) t++; ++ while (t < md->end_subject && !IS_NEWLINE(t)) t++; + end_subject = t; + } + +@@ -3753,11 +3988,9 @@ + + else if (startline) + { +- if (start_match >= md->start_subject + md->nllen + +- start_offset) ++ if (start_match > md->start_subject + start_offset) + { +- while (start_match <= end_subject && +- !IS_NEWLINE(start_match - md->nllen)) ++ while (start_match <= end_subject && !WAS_NEWLINE(start_match)) + start_match++; + } + } +@@ -3793,8 +4026,8 @@ + + HOWEVER: when the subject string is very, very long, searching to its end can + take a long time, and give bad performance on quite ordinary patterns. This +- showed up when somebody was matching /^C/ on a 32-megabyte string... so we +- don't do this when the string is sufficiently long. ++ showed up when somebody was matching something like /^\d+C/ on a 32-megabyte ++ string... so we don't do this when the string is sufficiently long. + + ALSO: this processing is disabled when partial matching is requested. + */ +@@ -3826,9 +4059,14 @@ + } + } + +- /* If we can't find the required character, break the matching loop */ ++ /* If we can't find the required character, break the matching loop, ++ forcing a match failure. */ + +- if (p >= end_subject) break; ++ if (p >= end_subject) ++ { ++ rc = MATCH_NOMATCH; ++ break; ++ } + + /* If we have found the required character, save the point where we + found it, so that we don't search again next time round the loop if +@@ -3838,49 +4076,70 @@ + } + } + +- /* When a match occurs, substrings will be set for all internal extractions; +- we just need to set up the whole thing as substring 0 before returning. If +- there were too many extractions, set the return code to zero. In the case +- where we had to get some local store to hold offsets for backreferences, copy +- those back references that we can. In this case there need not be overflow +- if certain parts of the pattern were not used. */ ++ /* OK, we can now run the match. */ + + md->start_match = start_match; + md->match_call_count = 0; ++ md->eptrn = 0; /* Next free eptrchain slot */ ++ rc = match(start_match, md->start_code, 2, md, ims, NULL, 0, 0); + +- rc = match(start_match, md->start_code, 2, md, ims, NULL, match_isgroup, 0); ++ /* Any return other than MATCH_NOMATCH breaks the loop. */ + +- /* When the result is no match, if the subject's first character was a +- newline and the PCRE_FIRSTLINE option is set, break (which will return +- PCRE_ERROR_NOMATCH). The option requests that a match occur before the first +- newline in the subject. Otherwise, advance the pointer to the next character +- and continue - but the continuation will actually happen only when the +- pattern is not anchored. */ ++ if (rc != MATCH_NOMATCH) break; + +- if (rc == MATCH_NOMATCH) +- { +- if (firstline && +- start_match <= md->end_subject - md->nllen && +- IS_NEWLINE(start_match)) +- break; +- start_match++; ++ /* If PCRE_FIRSTLINE is set, the match must happen before or at the first ++ newline in the subject (though it may continue over the newline). Therefore, ++ if we have just failed to match, starting at a newline, do not continue. */ ++ ++ if (firstline && IS_NEWLINE(start_match)) break; ++ ++ /* Advance the match position by one character. */ ++ ++ start_match++; + #ifdef SUPPORT_UTF8 +- if (md->utf8) +- while(start_match < end_subject && (*start_match & 0xc0) == 0x80) +- start_match++; ++ if (utf8) ++ while(start_match < end_subject && (*start_match & 0xc0) == 0x80) ++ start_match++; + #endif +- continue; +- } + +- if (rc != MATCH_MATCH) +- { +- DPRINTF((">>>> error: returning %d\n", rc)); +- return rc; +- } ++ /* Break the loop if the pattern is anchored or if we have passed the end of ++ the subject. */ ++ ++ if (anchored || start_match > end_subject) break; ++ ++ /* If we have just passed a CR and the newline option is CRLF or ANY, and we ++ are now at a LF, advance the match position by one more character. */ ++ ++ if (start_match[-1] == '\r' && ++ (md->nltype == NLTYPE_ANY || md->nllen == 2) && ++ start_match < end_subject && ++ *start_match == '\n') ++ start_match++; ++ ++ } /* End of for(;;) "bumpalong" loop */ ++ ++/* ==========================================================================*/ ++ ++/* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping ++conditions is true: + +- /* We have a match! Copy the offset information from temporary store if +- necessary */ ++(1) The pattern is anchored; + ++(2) We are past the end of the subject; ++ ++(3) PCRE_FIRSTLINE is set and we have failed to match at a newline, because ++ this option requests that a match occur at or before the first newline in ++ the subject. ++ ++When we have a match and the offset vector is big enough to deal with any ++backreferences, captured substring offsets will already be set up. In the case ++where we had to get some local store to hold offsets for backreference ++processing, copy those that we can. In this case there need not be overflow if ++certain parts of the pattern were not used, even though there are more ++capturing parentheses than vector slots. */ ++ ++if (rc == MATCH_MATCH) ++ { + if (using_temporary_offsets) + { + if (offsetcount >= 4) +@@ -3889,15 +4148,18 @@ + (offsetcount - 2) * sizeof(int)); + DPRINTF(("Copied offsets from temporary memory\n")); + } +- if (md->end_offset_top > offsetcount) +- md->offset_overflow = TRUE; +- ++ if (md->end_offset_top > offsetcount) md->offset_overflow = TRUE; + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(md->offset_vector); + } + ++ /* Set the return code to the number of captured strings, or 0 if there are ++ too many to fit into the vector. */ ++ + rc = md->offset_overflow? 0 : md->end_offset_top/2; + ++ /* If there is space, set up the whole thing as substring 0. */ ++ + if (offsetcount < 2) rc = 0; else + { + offsets[0] = start_match - md->start_subject; +@@ -3908,9 +4170,8 @@ + return rc; + } + +-/* This "while" is the end of the "do" above */ +- +-while (!anchored && start_match <= end_subject); ++/* Control gets here if there has been an error, or if the overall match ++attempt has failed at all permitted starting positions. */ + + if (using_temporary_offsets) + { +@@ -3918,7 +4179,12 @@ + (pcre_free)(md->offset_vector); + } + +-if (md->partial && md->hitend) ++if (rc != MATCH_NOMATCH) ++ { ++ DPRINTF((">>>> error: returning %d\n", rc)); ++ return rc; ++ } ++else if (md->partial && md->hitend) + { + DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n")); + return PCRE_ERROR_PARTIAL; +diff -ruN ../pcre.orig/pcrelib/pcre_globals.c ./pcrelib/pcre_globals.c +--- ../pcre.orig/pcrelib/pcre_globals.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_globals.c Fri Feb 9 22:31:19 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -51,6 +51,18 @@ + + + #ifndef VPCOMPAT ++ ++/************************************************************************** ++This code used to be here for use when compiling as a C++ library. However, ++according to Dair Grant it is not needed: " ++ ++ Including 'extern "C"' in the declaration generates an "initialized and ++ declared `extern'" warning from gcc 4.0.1. Since we include pcre_internal.h, ++ which includes pcre.h, which declares these prototypes within an extern "C" {} ++ block, we shouldn't need the prefix here. ++ ++So, from Release 7.0 I have cut this out. ++ + #ifdef __cplusplus + extern "C" void *(*pcre_malloc)(size_t) = malloc; + extern "C" void (*pcre_free)(void *) = free; +@@ -58,12 +70,13 @@ + extern "C" void (*pcre_stack_free)(void *) = free; + extern "C" int (*pcre_callout)(pcre_callout_block *) = NULL; + #else ++**************************************************************************/ ++ + void *(*pcre_malloc)(size_t) = malloc; + void (*pcre_free)(void *) = free; + void *(*pcre_stack_malloc)(size_t) = malloc; + void (*pcre_stack_free)(void *) = free; + int (*pcre_callout)(pcre_callout_block *) = NULL; +-#endif + #endif + + /* End of pcre_globals.c */ +diff -ruN ../pcre.orig/pcrelib/pcre_internal.h ./pcrelib/pcre_internal.h +--- ../pcre.orig/pcrelib/pcre_internal.h Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_internal.h Fri Feb 9 22:31:20 2007 +@@ -7,7 +7,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -54,12 +54,16 @@ + /* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef + inline, and there are *still* stupid compilers about that don't like indented + pre-processor statements, or at least there were when I first wrote this. After +-all, it had only been about 10 years then... */ ++all, it had only been about 10 years then... + ++It turns out that the Mac Debugging.h header also defines the macro DPRINTF, so ++be absolutely sure we get our version. */ ++ ++#undef DPRINTF + #ifdef DEBUG + #define DPRINTF(p) printf p + #else +-#define DPRINTF(p) /*nothing*/ ++#define DPRINTF(p) /* Nothing */ + #endif + + +@@ -118,13 +122,48 @@ + + typedef unsigned char uschar; + +-/* PCRE is able to support 3 different kinds of newline (CR, LF, CRLF). The +-following macro is used to package up testing for newlines. NLBLOCK is defined +-in the various modules to indicate in which datablock the parameters exist. */ ++/* This is an unsigned int value that no character can ever have. UTF-8 ++characters only go up to 0x7fffffff (though Unicode doesn't go beyond ++0x0010ffff). */ ++ ++#define NOTACHAR 0xffffffff ++ ++/* PCRE is able to support several different kinds of newline (CR, LF, CRLF, ++and "all" at present). The following macros are used to package up testing for ++newlines. NLBLOCK, PSSTART, and PSEND are defined in the various modules to ++indicate in which datablock the parameters exist, and what the start/end of ++string field names are. */ ++ ++#define NLTYPE_FIXED 0 /* Newline is a fixed length string */ ++#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */ ++ ++/* This macro checks for a newline at the given position */ + + #define IS_NEWLINE(p) \ +- ((p)[0] == NLBLOCK->nl[0] && \ +- (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1])) ++ ((NLBLOCK->nltype != NLTYPE_FIXED)? \ ++ ((p) < NLBLOCK->PSEND && \ ++ _pcre_is_newline((p), NLBLOCK->PSEND, &(NLBLOCK->nllen), utf8) \ ++ ) \ ++ : \ ++ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ ++ (p)[0] == NLBLOCK->nl[0] && \ ++ (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \ ++ ) \ ++ ) ++ ++/* This macro checks for a newline immediately preceding the given position */ ++ ++#define WAS_NEWLINE(p) \ ++ ((NLBLOCK->nltype != NLTYPE_FIXED)? \ ++ ((p) > NLBLOCK->PSSTART && \ ++ _pcre_was_newline((p), NLBLOCK->PSSTART, &(NLBLOCK->nllen), utf8) \ ++ ) \ ++ : \ ++ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ ++ (p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \ ++ (NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \ ++ ) \ ++ ) + + /* When PCRE is compiled as a C++ library, the subject pointer can be replaced + with a custom type. This makes it possible, for example, to allow pcre_exec() +@@ -282,7 +321,7 @@ + + #define GETCHAR(c, eptr) \ + c = *eptr; \ +- if ((c & 0xc0) == 0xc0) \ ++ if (c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ +@@ -300,7 +339,7 @@ + + #define GETCHARTEST(c, eptr) \ + c = *eptr; \ +- if (utf8 && (c & 0xc0) == 0xc0) \ ++ if (utf8 && c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ +@@ -318,7 +357,7 @@ + + #define GETCHARINC(c, eptr) \ + c = *eptr++; \ +- if ((c & 0xc0) == 0xc0) \ ++ if (c >= 0xc0) \ + { \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ +@@ -334,7 +373,7 @@ + + #define GETCHARINCTEST(c, eptr) \ + c = *eptr++; \ +- if (utf8 && (c & 0xc0) == 0xc0) \ ++ if (utf8 && c >= 0xc0) \ + { \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ + int gcss = 6*gcaa; \ +@@ -351,7 +390,7 @@ + + #define GETCHARLEN(c, eptr, len) \ + c = *eptr; \ +- if ((c & 0xc0) == 0xc0) \ ++ if (c >= 0xc0) \ + { \ + int gcii; \ + int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ +@@ -404,20 +443,21 @@ + /* Masks for identifying the public options that are permitted at compile + time, run time, or study time, respectively. */ + ++#define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY) ++ + #define PUBLIC_OPTIONS \ + (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ + PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ + PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ +- PCRE_DUPNAMES|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF) ++ PCRE_DUPNAMES|PCRE_NEWLINE_BITS) + + #define PUBLIC_EXEC_OPTIONS \ + (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ +- PCRE_PARTIAL|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF) ++ PCRE_PARTIAL|PCRE_NEWLINE_BITS) + + #define PUBLIC_DFA_EXEC_OPTIONS \ + (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ +- PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_CR| \ +- PCRE_NEWLINE_LF) ++ PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_BITS) + + #define PUBLIC_STUDY_OPTIONS 0 /* None defined */ + +@@ -449,9 +489,7 @@ + #define FALSE 0 + #define TRUE 1 + +-/* Escape items that are just an encoding of a particular data value. Note that +-ESC_n is defined as yet another macro, which is set in config.h to either \n +-(the default) or \r (which some people want). */ ++/* Escape items that are just an encoding of a particular data value. */ + + #ifndef ESC_e + #define ESC_e 27 +@@ -462,7 +500,7 @@ + #endif + + #ifndef ESC_n +-#define ESC_n NEWLINE ++#define ESC_n '\n' + #endif + + #ifndef ESC_r +@@ -501,21 +539,28 @@ + their negation. Also, they must appear in the same order as in the opcode + definitions below, up to ESC_z. There's a dummy for OP_ANY because it + corresponds to "." rather than an escape sequence. The final one must be +-ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two +-tests in the code for an escape greater than ESC_b and less than ESC_Z to +-detect the types that may be repeated. These are the types that consume +-characters. If any new escapes are put in between that don't consume a ++ESC_REF as subsequent values are used for backreferences (\1, \2, \3, etc). ++There are two tests in the code for an escape greater than ESC_b and less than ++ESC_Z to detect the types that may be repeated. These are the types that ++consume characters. If any new escapes are put in between that don't consume a + character, that code will have to change. */ + + enum { ESC_A = 1, ESC_G, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, +- ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_X, ESC_Z, ESC_z, ESC_E, +- ESC_Q, ESC_REF }; ++ ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_R, ESC_X, ESC_Z, ESC_z, ++ ESC_E, ESC_Q, ESC_k, ESC_REF }; ++ + + /* Opcode table: OP_BRA must be last, as all values >= it are used for brackets + that extract substrings. Starting from 1 (i.e. after OP_END), the values up to + OP_EOD must correspond in order to the list of escapes immediately above. +-Note that whenever this list is updated, the two macro definitions that follow +-must also be updated to match. */ ++ ++To keep stored, compiled patterns compatible, new opcodes should be added ++immediately before OP_BRA, where (since release 7.0) a gap is left for this ++purpose. ++ ++*** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definitions ++that follow must also be updated to match. There is also a table called ++"coptable" in pcre_dfa_exec.c that must be updated. */ + + enum { + OP_END, /* 0 End of pattern */ +@@ -536,110 +581,122 @@ + OP_ANYBYTE, /* 12 Match any byte (\C); different to OP_ANY for UTF-8 */ + OP_NOTPROP, /* 13 \P (not Unicode property) */ + OP_PROP, /* 14 \p (Unicode property) */ +- OP_EXTUNI, /* 15 \X (extended Unicode sequence */ +- OP_EODN, /* 16 End of data or \n at end of data: \Z. */ +- OP_EOD, /* 17 End of data: \z */ +- +- OP_OPT, /* 18 Set runtime options */ +- OP_CIRC, /* 19 Start of line - varies with multiline switch */ +- OP_DOLL, /* 20 End of line - varies with multiline switch */ +- OP_CHAR, /* 21 Match one character, casefully */ +- OP_CHARNC, /* 22 Match one character, caselessly */ +- OP_NOT, /* 23 Match one character, not the following one */ +- +- OP_STAR, /* 24 The maximizing and minimizing versions of */ +- OP_MINSTAR, /* 25 all these opcodes must come in pairs, with */ +- OP_PLUS, /* 26 the minimizing one second. */ +- OP_MINPLUS, /* 27 This first set applies to single characters */ +- OP_QUERY, /* 28 */ +- OP_MINQUERY, /* 29 */ +- OP_UPTO, /* 30 From 0 to n matches */ +- OP_MINUPTO, /* 31 */ +- OP_EXACT, /* 32 Exactly n matches */ +- +- OP_NOTSTAR, /* 33 The maximizing and minimizing versions of */ +- OP_NOTMINSTAR, /* 34 all these opcodes must come in pairs, with */ +- OP_NOTPLUS, /* 35 the minimizing one second. */ +- OP_NOTMINPLUS, /* 36 This set applies to "not" single characters */ +- OP_NOTQUERY, /* 37 */ +- OP_NOTMINQUERY, /* 38 */ +- OP_NOTUPTO, /* 39 From 0 to n matches */ +- OP_NOTMINUPTO, /* 40 */ +- OP_NOTEXACT, /* 41 Exactly n matches */ +- +- OP_TYPESTAR, /* 42 The maximizing and minimizing versions of */ +- OP_TYPEMINSTAR, /* 43 all these opcodes must come in pairs, with */ +- OP_TYPEPLUS, /* 44 the minimizing one second. These codes must */ +- OP_TYPEMINPLUS, /* 45 be in exactly the same order as those above. */ +- OP_TYPEQUERY, /* 46 This set applies to character types such as \d */ +- OP_TYPEMINQUERY, /* 47 */ +- OP_TYPEUPTO, /* 48 From 0 to n matches */ +- OP_TYPEMINUPTO, /* 49 */ +- OP_TYPEEXACT, /* 50 Exactly n matches */ +- +- OP_CRSTAR, /* 51 The maximizing and minimizing versions of */ +- OP_CRMINSTAR, /* 52 all these opcodes must come in pairs, with */ +- OP_CRPLUS, /* 53 the minimizing one second. These codes must */ +- OP_CRMINPLUS, /* 54 be in exactly the same order as those above. */ +- OP_CRQUERY, /* 55 These are for character classes and back refs */ +- OP_CRMINQUERY, /* 56 */ +- OP_CRRANGE, /* 57 These are different to the three sets above. */ +- OP_CRMINRANGE, /* 58 */ ++ OP_ANYNL, /* 15 \R (any newline sequence) */ ++ OP_EXTUNI, /* 16 \X (extended Unicode sequence */ ++ OP_EODN, /* 17 End of data or \n at end of data: \Z. */ ++ OP_EOD, /* 18 End of data: \z */ ++ ++ OP_OPT, /* 19 Set runtime options */ ++ OP_CIRC, /* 20 Start of line - varies with multiline switch */ ++ OP_DOLL, /* 21 End of line - varies with multiline switch */ ++ OP_CHAR, /* 22 Match one character, casefully */ ++ OP_CHARNC, /* 23 Match one character, caselessly */ ++ OP_NOT, /* 24 Match one character, not the following one */ ++ ++ OP_STAR, /* 25 The maximizing and minimizing versions of */ ++ OP_MINSTAR, /* 26 these six opcodes must come in pairs, with */ ++ OP_PLUS, /* 27 the minimizing one second. */ ++ OP_MINPLUS, /* 28 This first set applies to single characters.*/ ++ OP_QUERY, /* 29 */ ++ OP_MINQUERY, /* 30 */ ++ ++ OP_UPTO, /* 31 From 0 to n matches */ ++ OP_MINUPTO, /* 32 */ ++ OP_EXACT, /* 33 Exactly n matches */ ++ ++ OP_POSSTAR, /* 34 Possessified star */ ++ OP_POSPLUS, /* 35 Possessified plus */ ++ OP_POSQUERY, /* 36 Posesssified query */ ++ OP_POSUPTO, /* 37 Possessified upto */ ++ ++ OP_NOTSTAR, /* 38 The maximizing and minimizing versions of */ ++ OP_NOTMINSTAR, /* 39 these six opcodes must come in pairs, with */ ++ OP_NOTPLUS, /* 40 the minimizing one second. They must be in */ ++ OP_NOTMINPLUS, /* 41 exactly the same order as those above. */ ++ OP_NOTQUERY, /* 42 This set applies to "not" single characters. */ ++ OP_NOTMINQUERY, /* 43 */ ++ ++ OP_NOTUPTO, /* 44 From 0 to n matches */ ++ OP_NOTMINUPTO, /* 45 */ ++ OP_NOTEXACT, /* 46 Exactly n matches */ ++ ++ OP_NOTPOSSTAR, /* 47 Possessified versions */ ++ OP_NOTPOSPLUS, /* 48 */ ++ OP_NOTPOSQUERY, /* 49 */ ++ OP_NOTPOSUPTO, /* 50 */ ++ ++ OP_TYPESTAR, /* 51 The maximizing and minimizing versions of */ ++ OP_TYPEMINSTAR, /* 52 these six opcodes must come in pairs, with */ ++ OP_TYPEPLUS, /* 53 the minimizing one second. These codes must */ ++ OP_TYPEMINPLUS, /* 54 be in exactly the same order as those above. */ ++ OP_TYPEQUERY, /* 55 This set applies to character types such as \d */ ++ OP_TYPEMINQUERY, /* 56 */ ++ ++ OP_TYPEUPTO, /* 57 From 0 to n matches */ ++ OP_TYPEMINUPTO, /* 58 */ ++ OP_TYPEEXACT, /* 59 Exactly n matches */ ++ ++ OP_TYPEPOSSTAR, /* 60 Possessified versions */ ++ OP_TYPEPOSPLUS, /* 61 */ ++ OP_TYPEPOSQUERY, /* 62 */ ++ OP_TYPEPOSUPTO, /* 63 */ ++ ++ OP_CRSTAR, /* 64 The maximizing and minimizing versions of */ ++ OP_CRMINSTAR, /* 65 all these opcodes must come in pairs, with */ ++ OP_CRPLUS, /* 66 the minimizing one second. These codes must */ ++ OP_CRMINPLUS, /* 67 be in exactly the same order as those above. */ ++ OP_CRQUERY, /* 68 These are for character classes and back refs */ ++ OP_CRMINQUERY, /* 69 */ ++ OP_CRRANGE, /* 70 These are different to the three sets above. */ ++ OP_CRMINRANGE, /* 71 */ + +- OP_CLASS, /* 59 Match a character class, chars < 256 only */ +- OP_NCLASS, /* 60 Same, but the bitmap was created from a negative ++ OP_CLASS, /* 72 Match a character class, chars < 256 only */ ++ OP_NCLASS, /* 73 Same, but the bitmap was created from a negative + class - the difference is relevant only when a UTF-8 + character > 255 is encountered. */ + +- OP_XCLASS, /* 61 Extended class for handling UTF-8 chars within the ++ OP_XCLASS, /* 74 Extended class for handling UTF-8 chars within the + class. This does both positive and negative. */ + +- OP_REF, /* 62 Match a back reference */ +- OP_RECURSE, /* 63 Match a numbered subpattern (possibly recursive) */ +- OP_CALLOUT, /* 64 Call out to external function if provided */ +- +- OP_ALT, /* 65 Start of alternation */ +- OP_KET, /* 66 End of group that doesn't have an unbounded repeat */ +- OP_KETRMAX, /* 67 These two must remain together and in this */ +- OP_KETRMIN, /* 68 order. They are for groups the repeat for ever. */ +- +- /* The assertions must come before ONCE and COND */ +- +- OP_ASSERT, /* 69 Positive lookahead */ +- OP_ASSERT_NOT, /* 70 Negative lookahead */ +- OP_ASSERTBACK, /* 71 Positive lookbehind */ +- OP_ASSERTBACK_NOT, /* 72 Negative lookbehind */ +- OP_REVERSE, /* 73 Move pointer back - used in lookbehind assertions */ +- +- /* ONCE and COND must come after the assertions, with ONCE first, as there's +- a test for >= ONCE for a subpattern that isn't an assertion. */ +- +- OP_ONCE, /* 74 Once matched, don't back up into the subpattern */ +- OP_COND, /* 75 Conditional group */ +- OP_CREF, /* 76 Used to hold an extraction string number (cond ref) */ +- +- OP_BRAZERO, /* 77 These two must remain together and in this */ +- OP_BRAMINZERO, /* 78 order. */ +- +- OP_BRANUMBER, /* 79 Used for extracting brackets whose number is greater +- than can fit into an opcode. */ +- +- OP_BRA /* 80 This and greater values are used for brackets that +- extract substrings up to EXTRACT_BASIC_MAX. After +- that, use is made of OP_BRANUMBER. */ +-}; +- +-/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and +-study.c that all opcodes are less than 128 in value. This makes handling UTF-8 +-character sequences easier. */ +- +-/* The highest extraction number before we have to start using additional +-bytes. (Originally PCRE didn't have support for extraction counts highter than +-this number.) The value is limited by the number of opcodes left after OP_BRA, +-i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional +-opcodes. */ ++ OP_REF, /* 75 Match a back reference */ ++ OP_RECURSE, /* 76 Match a numbered subpattern (possibly recursive) */ ++ OP_CALLOUT, /* 77 Call out to external function if provided */ ++ ++ OP_ALT, /* 78 Start of alternation */ ++ OP_KET, /* 79 End of group that doesn't have an unbounded repeat */ ++ OP_KETRMAX, /* 80 These two must remain together and in this */ ++ OP_KETRMIN, /* 81 order. They are for groups the repeat for ever. */ ++ ++ /* The assertions must come before BRA, CBRA, ONCE, and COND.*/ ++ ++ OP_ASSERT, /* 82 Positive lookahead */ ++ OP_ASSERT_NOT, /* 83 Negative lookahead */ ++ OP_ASSERTBACK, /* 84 Positive lookbehind */ ++ OP_ASSERTBACK_NOT, /* 85 Negative lookbehind */ ++ OP_REVERSE, /* 86 Move pointer back - used in lookbehind assertions */ ++ ++ /* ONCE, BRA, CBRA, and COND must come after the assertions, with ONCE first, ++ as there's a test for >= ONCE for a subpattern that isn't an assertion. */ ++ ++ OP_ONCE, /* 87 Atomic group */ ++ OP_BRA, /* 88 Start of non-capturing bracket */ ++ OP_CBRA, /* 89 Start of capturing bracket */ ++ OP_COND, /* 90 Conditional group */ ++ ++ /* These three must follow the previous three, in the same order. There's a ++ check for >= SBRA to distinguish the two sets. */ ++ ++ OP_SBRA, /* 91 Start of non-capturing bracket, check empty */ ++ OP_SCBRA, /* 92 Start of capturing bracket, check empty */ ++ OP_SCOND, /* 93 Conditional group, check empty */ ++ ++ OP_CREF, /* 94 Used to hold a capture number as condition */ ++ OP_RREF, /* 95 Used to hold a recursion number as condition */ ++ OP_DEF, /* 96 The DEFINE condition */ + +-#define EXTRACT_BASIC_MAX 100 ++ OP_BRAZERO, /* 97 These two must remain together and in this */ ++ OP_BRAMINZERO /* 98 order. */ ++}; + + + /* This macro defines textual names for all the opcodes. These are used only +@@ -648,17 +705,21 @@ + #define OP_NAME_LIST \ + "End", "\\A", "\\G", "\\B", "\\b", "\\D", "\\d", \ + "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", \ +- "notprop", "prop", "extuni", \ ++ "notprop", "prop", "anynl", "extuni", \ + "\\Z", "\\z", \ + "Opt", "^", "$", "char", "charnc", "not", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ ++ "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ ++ "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ ++ "*+","++", "?+", "{", \ + "*", "*?", "+", "+?", "?", "??", "{", "{", \ + "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ + "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ +- "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cond ref",\ +- "Brazero", "Braminzero", "Branumber", "Bra" ++ "AssertB", "AssertB not", "Reverse", \ ++ "Once", "Bra 0", "Bra", "Cond", "SBra 0", "SBra", "SCond", \ ++ "Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero" + + + /* This macro defines the length of fixed length operations in the compiled +@@ -674,7 +735,7 @@ + 1, /* End */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \ + 1, 1, /* Any, Anybyte */ \ +- 3, 3, 1, /* NOTPROP, PROP, EXTUNI */ \ ++ 3, 3, 1, 1, /* NOTPROP, PROP, EXTUNI, ANYNL */ \ + 1, 1, 2, 1, 1, /* \Z, \z, Opt, ^, $ */ \ + 2, /* Char - the minimum length */ \ + 2, /* Charnc - the minimum length */ \ +@@ -682,12 +743,15 @@ + /* Positive single-char repeats ** These are */ \ + 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \ + 4, 4, 4, /* upto, minupto, exact ** UTF-8 mode */ \ ++ 2, 2, 2, 4, /* *+, ++, ?+, upto+ */ \ + /* Negative single-char repeats - only for chars < 256 */ \ + 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ + 4, 4, 4, /* NOT upto, minupto, exact */ \ ++ 2, 2, 2, 4, /* Possessive *, +, ?, upto */ \ + /* Positive type repeats */ \ + 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ + 4, 4, 4, /* Type upto, minupto, exact */ \ ++ 2, 2, 2, 4, /* Possessive *+, ++, ?+, upto+ */ \ + /* Character class & ref repeats */ \ + 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ + 5, 5, /* CRRANGE, CRMINRANGE */ \ +@@ -706,17 +770,22 @@ + 1+LINK_SIZE, /* Assert behind */ \ + 1+LINK_SIZE, /* Assert behind not */ \ + 1+LINK_SIZE, /* Reverse */ \ +- 1+LINK_SIZE, /* Once */ \ ++ 1+LINK_SIZE, /* ONCE */ \ ++ 1+LINK_SIZE, /* BRA */ \ ++ 3+LINK_SIZE, /* CBRA */ \ + 1+LINK_SIZE, /* COND */ \ ++ 1+LINK_SIZE, /* SBRA */ \ ++ 3+LINK_SIZE, /* SCBRA */ \ ++ 1+LINK_SIZE, /* SCOND */ \ + 3, /* CREF */ \ ++ 3, /* RREF */ \ ++ 1, /* DEF */ \ + 1, 1, /* BRAZERO, BRAMINZERO */ \ +- 3, /* BRANUMBER */ \ +- 1+LINK_SIZE /* BRA */ \ + + +-/* A magic value for OP_CREF to indicate the "in recursion" condition. */ ++/* A magic value for OP_RREF to indicate the "any recursion" condition. */ + +-#define CREF_RECURSE 0xffff ++#define RREF_ANY 0xffff + + /* Error code numbers. They are given names so that they can more easily be + tracked. */ +@@ -726,7 +795,7 @@ + ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, + ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, + ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, +- ERR50, ERR51 }; ++ ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57 }; + + /* The real format of the start of the pcre block; the index of names and the + code vector run on as long as necessary after the end. We store an explicit +@@ -781,17 +850,23 @@ + const uschar *fcc; /* Points to case-flipping table */ + const uschar *cbits; /* Points to character type table */ + const uschar *ctypes; /* Points to table of type maps */ ++ const uschar *start_workspace;/* The start of working space */ + const uschar *start_code; /* The start of the compiled code */ + const uschar *start_pattern; /* The start of the pattern */ ++ const uschar *end_pattern; /* The end of the pattern */ ++ uschar *hwm; /* High watermark of workspace */ + uschar *name_table; /* The name/number table */ + int names_found; /* Number of entries so far */ + int name_entry_size; /* Size of each entry */ ++ int bracount; /* Count of capturing parens */ + int top_backref; /* Maximum back reference */ + unsigned int backref_map; /* Bitmap of low back refs */ ++ int external_options; /* External (initial) options */ + int req_varyopt; /* "After variable item" flag for reqbyte */ + BOOL nopartial; /* Set TRUE if partial won't work */ +- int nllen; /* 1 or 2 for newline string length */ +- uschar nl[4]; /* Newline string */ ++ int nltype; /* Newline type */ ++ int nllen; /* Newline string length */ ++ uschar nl[4]; /* Newline string when fixed length */ + } compile_data; + + /* Structure for maintaining a chain of pointers to the currently incomplete +@@ -824,6 +899,16 @@ + + struct heapframe; + ++/* Structure for building a chain of data for holding the values of the subject ++pointer at the start of each subpattern, so as to detect when an empty string ++has been matched by a subpattern - to break infinite loops. */ ++ ++typedef struct eptrblock { ++ struct eptrblock *epb_prev; ++ USPTR epb_saved_eptr; ++} eptrblock; ++ ++ + /* Structure for passing "static" information around between the functions + doing traditional NFA matching, so that they are thread-safe. */ + +@@ -834,8 +919,9 @@ + int *offset_vector; /* Offset vector */ + int offset_end; /* One past the end */ + int offset_max; /* The maximum usable for return data */ +- int nllen; /* 1 or 2 for newline string length */ +- uschar nl[4]; /* Newline string */ ++ int nltype; /* Newline type */ ++ int nllen; /* Newline string length */ ++ uschar nl[4]; /* Newline string when fixed */ + const uschar *lcc; /* Points to lower casing table */ + const uschar *ctypes; /* Points to table of type maps */ + BOOL offset_overflow; /* Set if too many extractions */ +@@ -854,6 +940,8 @@ + int end_offset_top; /* Highwater mark at end of match */ + int capture_last; /* Most recent capture number */ + int start_offset; /* The start offset value */ ++ eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */ ++ int eptrn; /* Next free eptrblock */ + recursion_info *recursive; /* Linked list of recursion data */ + void *callout_data; /* To pass back to callouts */ + struct heapframe *thisframe; /* Used only when compiling for no recursion */ +@@ -869,8 +957,9 @@ + const uschar *tables; /* Character tables */ + int moptions; /* Match options */ + int poptions; /* Pattern options */ +- int nllen; /* 1 or 2 for newline string length */ +- uschar nl[4]; /* Newline string */ ++ int nltype; /* Newline type */ ++ int nllen; /* Newline string length */ ++ uschar nl[4]; /* Newline string when fixed */ + void *callout_data; /* To pass back to callouts */ + } dfa_match_data; + +@@ -941,13 +1030,17 @@ + one of the exported public functions. They have to be "external" in the C + sense, but are not part of the PCRE public API. */ + +-extern int _pcre_ord2utf8(int, uschar *); +-extern real_pcre * _pcre_try_flipped(const real_pcre *, real_pcre *, +- const pcre_study_data *, pcre_study_data *); +-extern int _pcre_ucp_findprop(const unsigned int, int *, int *); +-extern int _pcre_ucp_othercase(const int); +-extern int _pcre_valid_utf8(const uschar *, int); +-extern BOOL _pcre_xclass(int, const uschar *); ++extern BOOL _pcre_is_newline(const uschar *, const uschar *, int *, ++ BOOL); ++extern int _pcre_ord2utf8(int, uschar *); ++extern real_pcre *_pcre_try_flipped(const real_pcre *, real_pcre *, ++ const pcre_study_data *, pcre_study_data *); ++extern int _pcre_ucp_findprop(const unsigned int, int *, int *); ++extern unsigned int _pcre_ucp_othercase(const unsigned int); ++extern int _pcre_valid_utf8(const uschar *, int); ++extern BOOL _pcre_was_newline(const uschar *, const uschar *, int *, ++ BOOL); ++extern BOOL _pcre_xclass(int, const uschar *); + + #endif + +diff -ruN ../pcre.orig/pcrelib/pcre_maketables.c ./pcrelib/pcre_maketables.c +--- ../pcre.orig/pcrelib/pcre_maketables.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_maketables.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -130,7 +130,7 @@ + meta-character, which in this sense is any character that terminates a run + of data characters. */ + +- if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; ++ if (strchr("\\*+?{^.$|()[", i) != 0) x += ctype_meta; + *p++ = x; + } + +diff -ruN ../pcre.orig/pcrelib/pcre_newline.c ./pcrelib/pcre_newline.c +--- ../pcre.orig/pcrelib/pcre_newline.c Thu Jan 1 01:00:00 1970 ++++ ./pcrelib/pcre_newline.c Fri Feb 9 20:48:47 2007 +@@ -0,0 +1,135 @@ ++/************************************************* ++* Perl-Compatible Regular Expressions * ++*************************************************/ ++ ++/* PCRE is a library of functions to support regular expressions whose syntax ++and semantics are as close as possible to those of the Perl 5 language. ++ ++ Written by Philip Hazel ++ Copyright (c) 1997-2006 University of Cambridge ++ ++----------------------------------------------------------------------------- ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are met: ++ ++ * Redistributions of source code must retain the above copyright notice, ++ this list of conditions and the following disclaimer. ++ ++ * Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ ++ * Neither the name of the University of Cambridge nor the names of its ++ contributors may be used to endorse or promote products derived from ++ this software without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGE. ++----------------------------------------------------------------------------- ++*/ ++ ++ ++/* This module contains internal functions for testing newlines when more than ++one kind of newline is to be recognized. When a newline is found, its length is ++returned. In principle, we could implement several newline "types", each ++referring to a different set of newline characters. At present, PCRE supports ++only NLTYPE_FIXED, which gets handled without these functions, and NLTYPE_ALL, ++so for now the type isn't passed into the functions. It can easily be added ++later if required. The full list of Unicode newline characters is taken from ++http://unicode.org/unicode/reports/tr18/. */ ++ ++ ++#include "pcre_internal.h" ++ ++ ++ ++/************************************************* ++* Check for newline at given position * ++*************************************************/ ++ ++/* It is guaranteed that the initial value of ptr is less than the end of the ++string that is being processed. ++ ++Arguments: ++ ptr pointer to possible newline ++ endptr pointer to the end of the string ++ lenptr where to return the length ++ utf8 TRUE if in utf8 mode ++ ++Returns: TRUE or FALSE ++*/ ++ ++BOOL ++_pcre_is_newline(const uschar *ptr, const uschar *endptr, int *lenptr, ++ BOOL utf8) ++{ ++int c; ++if (utf8) { GETCHAR(c, ptr); } else c = *ptr; ++switch(c) ++ { ++ case 0x000a: /* LF */ ++ case 0x000b: /* VT */ ++ case 0x000c: *lenptr = 1; return TRUE; /* FF */ ++ case 0x000d: *lenptr = (ptr < endptr - 1 && ptr[1] == 0x0a)? 2 : 1; ++ return TRUE; /* CR */ ++ case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ ++ case 0x2028: /* LS */ ++ case 0x2029: *lenptr = 3; return TRUE; /* PS */ ++ default: return FALSE; ++ } ++} ++ ++ ++ ++/************************************************* ++* Check for newline at previous position * ++*************************************************/ ++ ++/* It is guaranteed that the initial value of ptr is greater than the start of ++the string that is being processed. ++ ++Arguments: ++ ptr pointer to possible newline ++ startptr pointer to the start of the string ++ lenptr where to return the length ++ utf8 TRUE if in utf8 mode ++ ++Returns: TRUE or FALSE ++*/ ++ ++BOOL ++_pcre_was_newline(const uschar *ptr, const uschar *startptr, int *lenptr, ++ BOOL utf8) ++{ ++int c; ++ptr--; ++if (utf8) ++ { ++ BACKCHAR(ptr); ++ GETCHAR(c, ptr); ++ } ++else c = *ptr; ++switch(c) ++ { ++ case 0x000a: *lenptr = (ptr > startptr && ptr[-1] == 0x0d)? 2 : 1; ++ return TRUE; /* LF */ ++ case 0x000b: /* VT */ ++ case 0x000c: /* FF */ ++ case 0x000d: *lenptr = 1; return TRUE; /* CR */ ++ case 0x0085: *lenptr = utf8? 2 : 1; return TRUE; /* NEL */ ++ case 0x2028: /* LS */ ++ case 0x2029: *lenptr = 3; return TRUE; /* PS */ ++ default: return FALSE; ++ } ++} ++ ++/* End of pcre_newline.c */ +diff -ruN ../pcre.orig/pcrelib/pcre_printint.src ./pcrelib/pcre_printint.src +--- ../pcre.orig/pcrelib/pcre_printint.src Wed Aug 30 22:00:22 2006 ++++ ./pcrelib/pcre_printint.src Fri Feb 9 22:31:20 2007 +@@ -49,9 +49,19 @@ + compiled regex for debugging purposes. */ + + ++/* Macro that decides whether a character should be output as a literal or in ++hexadecimal. We don't use isprint() because that can vary from system to system ++(even without the use of locales) and we want the output always to be the same, ++for testing purposes. This macro is used in pcretest as well as in this file. */ ++ ++#define PRINTABLE(c) ((c) >= 32 && (c) < 127) ++ ++/* The table of operator names. */ ++ + static const char *OP_names[] = { OP_NAME_LIST }; + + ++ + /************************************************* + * Print single- or multi-byte character * + *************************************************/ +@@ -63,7 +73,7 @@ + + if (!utf8 || (c & 0xc0) != 0xc0) + { +- if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c); ++ if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c); + return 0; + } + else +@@ -160,16 +170,6 @@ + + fprintf(f, "%3d ", (int)(code - codestart)); + +- if (*code >= OP_BRA) +- { +- if (*code - OP_BRA > EXTRACT_BASIC_MAX) +- fprintf(f, "%3d Bra extra\n", GET(code, 1)); +- else +- fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA); +- code += _pcre_OP_lengths[OP_BRA]; +- continue; +- } +- + switch(*code) + { + case OP_END: +@@ -203,6 +203,14 @@ + fprintf(f, "\n"); + continue; + ++ case OP_CBRA: ++ case OP_SCBRA: ++ fprintf(f, "%3d %s %d", GET(code, 1), OP_names[*code], ++ GET2(code, 1+LINK_SIZE)); ++ break; ++ ++ case OP_BRA: ++ case OP_SBRA: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_ALT: +@@ -213,33 +221,45 @@ + case OP_ASSERTBACK_NOT: + case OP_ONCE: + case OP_COND: ++ case OP_SCOND: + case OP_REVERSE: + fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]); + break; + +- case OP_BRANUMBER: +- printf("%3d %s", GET2(code, 1), OP_names[*code]); ++ case OP_CREF: ++ fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]); + break; + +- case OP_CREF: +- if (GET2(code, 1) == CREF_RECURSE) +- fprintf(f, " Cond recurse"); ++ case OP_RREF: ++ c = GET2(code, 1); ++ if (c == RREF_ANY) ++ fprintf(f, " Cond recurse any"); + else +- fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]); ++ fprintf(f, " Cond recurse %d", c); ++ break; ++ ++ case OP_DEF: ++ fprintf(f, " Cond def"); + break; + + case OP_STAR: + case OP_MINSTAR: ++ case OP_POSSTAR: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + case OP_QUERY: + case OP_MINQUERY: ++ case OP_POSQUERY: + case OP_TYPESTAR: + case OP_TYPEMINSTAR: ++ case OP_TYPEPOSSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: ++ case OP_TYPEPOSPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: ++ case OP_TYPEPOSQUERY: + fprintf(f, " "); + if (*code >= OP_TYPESTAR) + { +@@ -257,17 +277,20 @@ + case OP_EXACT: + case OP_UPTO: + case OP_MINUPTO: ++ case OP_POSUPTO: + fprintf(f, " "); + extra = print_char(f, code+3, utf8); + fprintf(f, "{"); +- if (*code != OP_EXACT) fprintf(f, ","); ++ if (*code != OP_EXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_MINUPTO) fprintf(f, "?"); ++ else if (*code == OP_POSUPTO) fprintf(f, "+"); + break; + + case OP_TYPEEXACT: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: ++ case OP_TYPEPOSUPTO: + fprintf(f, " %s", OP_names[code[3]]); + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) + { +@@ -278,20 +301,26 @@ + if (*code != OP_TYPEEXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_TYPEMINUPTO) fprintf(f, "?"); ++ else if (*code == OP_TYPEPOSUPTO) fprintf(f, "+"); + break; + + case OP_NOT: +- if (isprint(c = code[1])) fprintf(f, " [^%c]", c); ++ c = code[1]; ++ if (PRINTABLE(c)) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + break; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: ++ case OP_NOTPOSSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: ++ case OP_NOTPOSPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: +- if (isprint(c = code[1])) fprintf(f, " [^%c]", c); ++ case OP_NOTPOSQUERY: ++ c = code[1]; ++ if (PRINTABLE(c)) fprintf(f, " [^%c]", c); + else fprintf(f, " [^\\x%02x]", c); + fprintf(f, "%s", OP_names[*code]); + break; +@@ -299,11 +328,14 @@ + case OP_NOTEXACT: + case OP_NOTUPTO: + case OP_NOTMINUPTO: +- if (isprint(c = code[3])) fprintf(f, " [^%c]{", c); ++ case OP_NOTPOSUPTO: ++ c = code[3]; ++ if (PRINTABLE(c)) fprintf(f, " [^%c]{", c); + else fprintf(f, " [^\\x%02x]{", c); + if (*code != OP_NOTEXACT) fprintf(f, "0,"); + fprintf(f, "%d}", GET2(code,1)); + if (*code == OP_NOTMINUPTO) fprintf(f, "?"); ++ else if (*code == OP_NOTPOSUPTO) fprintf(f, "+"); + break; + + case OP_RECURSE: +@@ -363,12 +395,14 @@ + for (j = i+1; j < 256; j++) + if ((ccode[j/8] & (1 << (j&7))) == 0) break; + if (i == '-' || i == ']') fprintf(f, "\\"); +- if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i); ++ if (PRINTABLE(i)) fprintf(f, "%c", i); ++ else fprintf(f, "\\x%02x", i); + if (--j > i) + { + if (j != i + 1) fprintf(f, "-"); + if (j == '-' || j == ']') fprintf(f, "\\"); +- if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j); ++ if (PRINTABLE(j)) fprintf(f, "%c", j); ++ else fprintf(f, "\\x%02x", j); + } + i = j; + } +diff -ruN ../pcre.orig/pcrelib/pcre_scanner.cc ./pcrelib/pcre_scanner.cc +--- ../pcre.orig/pcrelib/pcre_scanner.cc Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/pcre_scanner.cc Fri Feb 9 22:31:20 2007 +@@ -43,6 +43,7 @@ + input_(data_), + skip_(NULL), + should_skip_(false), ++ skip_repeat_(false), + save_comments_(false), + comments_(NULL), + comments_offset_(0) { +@@ -53,6 +54,7 @@ + input_(data_), + skip_(NULL), + should_skip_(false), ++ skip_repeat_(false), + save_comments_(false), + comments_(NULL), + comments_offset_(0) { +@@ -63,15 +65,31 @@ + delete comments_; + } + ++void Scanner::SetSkipExpression(const char* re) { ++ delete skip_; ++ if (re != NULL) { ++ skip_ = new RE(re); ++ should_skip_ = true; ++ skip_repeat_ = true; ++ ConsumeSkip(); ++ } else { ++ skip_ = NULL; ++ should_skip_ = false; ++ skip_repeat_ = false; ++ } ++} ++ + void Scanner::Skip(const char* re) { + delete skip_; + if (re != NULL) { + skip_ = new RE(re); + should_skip_ = true; ++ skip_repeat_ = false; + ConsumeSkip(); + } else { + skip_ = NULL; + should_skip_ = false; ++ skip_repeat_ = false; + } + } + +@@ -118,19 +136,22 @@ + + // helper function to consume *skip_ and honour save_comments_ + void Scanner::ConsumeSkip() { ++ const char* start_data = input_.data(); ++ while (skip_->Consume(&input_)) { ++ if (!skip_repeat_) { ++ // Only one skip allowed. ++ break; ++ } ++ } + if (save_comments_) { +- if (NULL == comments_) { ++ if (comments_ == NULL) { + comments_ = new vector<StringPiece>; + } +- const char *start_data = input_.data(); +- skip_->Consume(&input_); + // already pointing one past end, so no need to +1 + int length = input_.data() - start_data; + if (length > 0) { + comments_->push_back(StringPiece(start_data, length)); + } +- } else { +- skip_->Consume(&input_); + } + } + +diff -ruN ../pcre.orig/pcrelib/pcre_scanner.h ./pcrelib/pcre_scanner.h +--- ../pcre.orig/pcrelib/pcre_scanner.h Tue Aug 9 01:59:00 2005 ++++ ./pcrelib/pcre_scanner.h Fri Feb 9 22:31:20 2007 +@@ -36,7 +36,7 @@ + // Scanner scanner(input); + // string var; + // int number; +-// scanner.Skip("\\s+"); // Skip any white space we encounter ++// scanner.SetSkipExpression("\\s+"); // Skip any white space we encounter + // while (scanner.Consume("(\\w+) = (\\d+)", &var, &number)) { + // ...; + // } +@@ -90,10 +90,16 @@ + // skipped. For example, a programming language scanner would use + // a skip RE that matches white space and comments. + // +- // scanner.Skip("(\\s|//.*|/[*](.|\n)*?[*]/)*"); ++ // scanner.SetSkipExpression("\\s+|//.*|/[*](.|\n)*?[*]/"); ++ // ++ // Skipping repeats as long as it succeeds. We used to let people do ++ // this by writing "(...)*" in the regular expression, but that added ++ // up to lots of recursive calls within the pcre library, so now we ++ // control repetition explicitly via the function call API. + // + // You can pass NULL for "re" if you do not want any data to be skipped. +- void Skip(const char* re); ++ void Skip(const char* re); // DEPRECATED; does *not* repeat ++ void SetSkipExpression(const char* re); + + // Temporarily pause "skip"ing. This + // Skip("Foo"); code ; DisableSkip(); code; EnableSkip() +@@ -109,12 +115,13 @@ + /***** Special wrappers around SetSkip() for some common idioms *****/ + + // Arranges to skip whitespace, C comments, C++ comments. +- // The overall RE is a repeated disjunction of the following REs: ++ // The overall RE is a disjunction of the following REs: + // \\s whitespace + // //.*\n C++ comment + // /[*](.|\n)*?[*]/ C comment (x*? means minimal repetitions of x) ++ // We get repetition via the semantics of SetSkipExpression, not by using * + void SkipCXXComments() { +- Skip("((\\s|//.*\n|/[*](.|\n)*?[*]/)*)"); ++ SetSkipExpression("\\s|//.*\n|/[*](?:\n|.)*?[*]/"); + } + + void set_save_comments(bool comments) { +@@ -143,6 +150,7 @@ + StringPiece input_; // Unprocessed input + RE* skip_; // If non-NULL, RE for skipping input + bool should_skip_; // If true, use skip_ ++ bool skip_repeat_; // If true, repeat skip_ as long as it works + bool save_comments_; // If true, aggregate the skip expression + + // the skipped comments +diff -ruN ../pcre.orig/pcrelib/pcre_scanner_unittest.cc ./pcrelib/pcre_scanner_unittest.cc +--- ../pcre.orig/pcrelib/pcre_scanner_unittest.cc Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/pcre_scanner_unittest.cc Fri Feb 9 22:31:20 2007 +@@ -33,10 +33,13 @@ + // functionality. + + #include <stdio.h> ++#include <string> + #include <vector> + #include <pcre_stringpiece.h> + #include <pcre_scanner.h> + ++#define FLAGS_unittest_stack_size 49152 ++ + // Dies with a fatal error if the two values are not equal. + #define CHECK_EQ(a, b) do { \ + if ( (a) != (b) ) { \ +@@ -116,8 +119,31 @@ + comments.resize(0); + } + ++static void TestBigComment() { ++ string input; ++ for (int i = 0; i < 1024; ++i) { ++ char buf[1024]; ++ snprintf(buf, sizeof(buf), " # Comment %d\n", i); ++ input += buf; ++ } ++ input += "name = value;\n"; ++ ++ Scanner s(input.c_str()); ++ s.SetSkipExpression("\\s+|#.*\n"); ++ ++ string name; ++ string value; ++ s.Consume("(\\w+) = (\\w+);", &name, &value); ++ CHECK_EQ(name, "name"); ++ CHECK_EQ(value, "value"); ++} ++ ++// TODO: also test scanner and big-comment in a thread with a ++// small stack size ++ + int main(int argc, char** argv) { + TestScanner(); ++ TestBigComment(); + + // Done + printf("OK\n"); +diff -ruN ../pcre.orig/pcrelib/pcre_study.c ./pcrelib/pcre_study.c +--- ../pcre.orig/pcrelib/pcre_study.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_study.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -45,6 +45,11 @@ + #include "pcre_internal.h" + + ++/* Returns from set_start_bits() */ ++ ++enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE }; ++ ++ + /************************************************* + * Set a bit and maybe its alternate case * + *************************************************/ +@@ -72,12 +77,16 @@ + + + /************************************************* +-* Create bitmap of starting chars * ++* Create bitmap of starting bytes * + *************************************************/ + +-/* This function scans a compiled unanchored expression and attempts to build a +-bitmap of the set of initial characters. If it can't, it returns FALSE. As time +-goes by, we may be able to get more clever at doing this. ++/* This function scans a compiled unanchored expression recursively and ++attempts to build a bitmap of the set of possible starting bytes. As time goes ++by, we may be able to get more clever at doing this. The SSB_CONTINUE return is ++useful for parenthesized groups in patterns such as (a*)b where the group ++provides some optional starting bytes but scanning must continue at the outer ++level to find at least one mandatory byte. At the outermost level, this ++function fails unless the result is SSB_DONE. + + Arguments: + code points to an expression +@@ -86,14 +95,17 @@ + utf8 TRUE if in UTF-8 mode + cd the block with char table pointers + +-Returns: TRUE if table built, FALSE otherwise ++Returns: SSB_FAIL => Failed to find any starting bytes ++ SSB_DONE => Found mandatory starting bytes ++ SSB_CONTINUE => Found optional starting bytes + */ + +-static BOOL ++static int + set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, + BOOL utf8, compile_data *cd) + { + register int c; ++int yield = SSB_DONE; + + #if 0 + /* ========================================================================= */ +@@ -114,36 +126,60 @@ + + do + { +- const uschar *tcode = code + 1 + LINK_SIZE; ++ const uschar *tcode = code + (((int)*code == OP_CBRA)? 3:1) + LINK_SIZE; + BOOL try_next = TRUE; + +- while (try_next) ++ while (try_next) /* Loop for items in this branch */ + { +- /* If a branch starts with a bracket or a positive lookahead assertion, +- recurse to set bits from within them. That's all for this branch. */ +- +- if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) ++ int rc; ++ switch(*tcode) + { +- if (!set_start_bits(tcode, start_bits, caseless, utf8, cd)) +- return FALSE; +- try_next = FALSE; +- } ++ /* Fail if we reach something we don't understand */ + +- else switch(*tcode) +- { + default: +- return FALSE; ++ return SSB_FAIL; + +- /* Skip over callout */ ++ /* If we hit a bracket or a positive lookahead assertion, recurse to set ++ bits from within the subpattern. If it can't find anything, we have to ++ give up. If it finds some mandatory character(s), we are done for this ++ branch. Otherwise, carry on scanning after the subpattern. */ ++ ++ case OP_BRA: ++ case OP_SBRA: ++ case OP_CBRA: ++ case OP_SCBRA: ++ case OP_ONCE: ++ case OP_ASSERT: ++ rc = set_start_bits(tcode, start_bits, caseless, utf8, cd); ++ if (rc == SSB_FAIL) return SSB_FAIL; ++ if (rc == SSB_DONE) try_next = FALSE; else ++ { ++ do tcode += GET(tcode, 1); while (*tcode == OP_ALT); ++ tcode += 1 + LINK_SIZE; ++ } ++ break; + +- case OP_CALLOUT: +- tcode += 2 + 2*LINK_SIZE; ++ /* If we hit ALT or KET, it means we haven't found anything mandatory in ++ this branch, though we might have found something optional. For ALT, we ++ continue with the next alternative, but we have to arrange that the final ++ result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET, ++ return SSB_CONTINUE: if this is the top level, that indicates failure, ++ but after a nested subpattern, it causes scanning to continue. */ ++ ++ case OP_ALT: ++ yield = SSB_CONTINUE; ++ try_next = FALSE; + break; + +- /* Skip over extended extraction bracket number */ ++ case OP_KET: ++ case OP_KETRMAX: ++ case OP_KETRMIN: ++ return SSB_CONTINUE; + +- case OP_BRANUMBER: +- tcode += 3; ++ /* Skip over callout */ ++ ++ case OP_CALLOUT: ++ tcode += 2 + 2*LINK_SIZE; + break; + + /* Skip over lookbehind and negative lookahead assertions */ +@@ -152,7 +188,7 @@ + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do tcode += GET(tcode, 1); while (*tcode == OP_ALT); +- tcode += 1+LINK_SIZE; ++ tcode += 1 + LINK_SIZE; + break; + + /* Skip over an option setting, changing the caseless flag */ +@@ -166,27 +202,30 @@ + + case OP_BRAZERO: + case OP_BRAMINZERO: +- if (!set_start_bits(++tcode, start_bits, caseless, utf8, cd)) +- return FALSE; ++ if (set_start_bits(++tcode, start_bits, caseless, utf8, cd) == SSB_FAIL) ++ return SSB_FAIL; + /* ========================================================================= + See the comment at the head of this function concerning the next line, + which was an old fudge for the benefit of OS/2. + dummy = 1; + ========================================================================= */ + do tcode += GET(tcode,1); while (*tcode == OP_ALT); +- tcode += 1+LINK_SIZE; ++ tcode += 1 + LINK_SIZE; + break; + + /* Single-char * or ? sets the bit and tries the next item */ + + case OP_STAR: + case OP_MINSTAR: ++ case OP_POSSTAR: + case OP_QUERY: + case OP_MINQUERY: ++ case OP_POSQUERY: + set_bit(start_bits, tcode[1], caseless, cd); + tcode += 2; + #ifdef SUPPORT_UTF8 +- if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++; ++ if (utf8 && tcode[-1] >= 0xc0) ++ tcode += _pcre_utf8_table4[tcode[-1] & 0x3f]; + #endif + break; + +@@ -194,10 +233,12 @@ + + case OP_UPTO: + case OP_MINUPTO: ++ case OP_POSUPTO: + set_bit(start_bits, tcode[3], caseless, cd); + tcode += 4; + #ifdef SUPPORT_UTF8 +- if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++; ++ if (utf8 && tcode[-1] >= 0xc0) ++ tcode += _pcre_utf8_table4[tcode[-1] & 0x3f]; + #endif + break; + +@@ -210,6 +251,7 @@ + case OP_CHARNC: + case OP_PLUS: + case OP_MINPLUS: ++ case OP_POSPLUS: + set_bit(start_bits, tcode[1], caseless, cd); + try_next = FALSE; + break; +@@ -283,16 +325,19 @@ + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: ++ case OP_TYPEPOSUPTO: + tcode += 2; /* Fall through */ + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: ++ case OP_TYPEPOSSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: ++ case OP_TYPEPOSQUERY: + switch(tcode[1]) + { + case OP_ANY: +- return FALSE; ++ return SSB_FAIL; + + case OP_NOT_DIGIT: + for (c = 0; c < 32; c++) +@@ -418,7 +463,7 @@ + code += GET(code, 1); /* Advance to next branch */ + } + while (*code == OP_ALT); +-return TRUE; ++return yield; + } + + +@@ -492,8 +537,8 @@ + /* See if we can find a fixed set of initial characters for the pattern. */ + + memset(start_bits, 0, 32 * sizeof(uschar)); +-if (!set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0, +- (re->options & PCRE_UTF8) != 0, &compile_block)) return NULL; ++if (set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0, ++ (re->options & PCRE_UTF8) != 0, &compile_block) != SSB_DONE) return NULL; + + /* Get a pcre_extra block and a pcre_study_data block. The study data is put in + the latter, which is pointed to by the former, which may also get additional +diff -ruN ../pcre.orig/pcrelib/pcre_tables.c ./pcrelib/pcre_tables.c +--- ../pcre.orig/pcrelib/pcre_tables.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_tables.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -72,9 +72,8 @@ + const int _pcre_utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; + const int _pcre_utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +-/* Table of the number of extra characters, indexed by the first character +-masked with 0x3f. The highest number for a valid UTF-8 character is in fact +-0x3d. */ ++/* Table of the number of extra bytes, indexed by the first byte masked with ++0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ + + const uschar _pcre_utf8_table4[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +@@ -89,6 +88,7 @@ + { "Any", PT_ANY, 0 }, + { "Arabic", PT_SC, ucp_Arabic }, + { "Armenian", PT_SC, ucp_Armenian }, ++ { "Balinese", PT_SC, ucp_Balinese }, + { "Bengali", PT_SC, ucp_Bengali }, + { "Bopomofo", PT_SC, ucp_Bopomofo }, + { "Braille", PT_SC, ucp_Braille }, +@@ -104,6 +104,7 @@ + { "Common", PT_SC, ucp_Common }, + { "Coptic", PT_SC, ucp_Coptic }, + { "Cs", PT_PC, ucp_Cs }, ++ { "Cuneiform", PT_SC, ucp_Cuneiform }, + { "Cypriot", PT_SC, ucp_Cypriot }, + { "Cyrillic", PT_SC, ucp_Cyrillic }, + { "Deseret", PT_SC, ucp_Deseret }, +@@ -146,6 +147,7 @@ + { "N", PT_GC, ucp_N }, + { "Nd", PT_PC, ucp_Nd }, + { "New_Tai_Lue", PT_SC, ucp_New_Tai_Lue }, ++ { "Nko", PT_SC, ucp_Nko }, + { "Nl", PT_PC, ucp_Nl }, + { "No", PT_PC, ucp_No }, + { "Ogham", PT_SC, ucp_Ogham }, +@@ -158,6 +160,8 @@ + { "Pd", PT_PC, ucp_Pd }, + { "Pe", PT_PC, ucp_Pe }, + { "Pf", PT_PC, ucp_Pf }, ++ { "Phags_Pa", PT_SC, ucp_Phags_Pa }, ++ { "Phoenician", PT_SC, ucp_Phoenician }, + { "Pi", PT_PC, ucp_Pi }, + { "Po", PT_PC, ucp_Po }, + { "Ps", PT_PC, ucp_Ps }, +diff -ruN ../pcre.orig/pcrelib/pcre_ucp_searchfuncs.c ./pcrelib/pcre_ucp_searchfuncs.c +--- ../pcre.orig/pcrelib/pcre_ucp_searchfuncs.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_ucp_searchfuncs.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -131,11 +131,11 @@ + Arguments: + c the character value + +-Returns: the other case or -1 if none ++Returns: the other case or NOTACHAR if none + */ + +-int +-_pcre_ucp_othercase(const int c) ++unsigned int ++_pcre_ucp_othercase(const unsigned int c) + { + int bot = 0; + int top = sizeof(ucp_table)/sizeof(cnode); +@@ -161,14 +161,14 @@ + } + } + +-/* Found an entry in the table. Return -1 for a range entry. Otherwise return +-the other case if there is one, else -1. */ ++/* Found an entry in the table. Return NOTACHAR for a range entry. Otherwise ++return the other case if there is one, else NOTACHAR. */ + +-if ((ucp_table[mid].f0 & f0_rangeflag) != 0) return -1; ++if ((ucp_table[mid].f0 & f0_rangeflag) != 0) return NOTACHAR; + + offset = ucp_table[mid].f1 & f1_casemask; + if ((offset & f1_caseneg) != 0) offset |= f1_caseneg; +-return (offset == 0)? -1 : c + offset; ++return (offset == 0)? NOTACHAR : c + offset; + } + + +diff -ruN ../pcre.orig/pcrelib/pcre_valid_utf8.c ./pcrelib/pcre_valid_utf8.c +--- ../pcre.orig/pcrelib/pcre_valid_utf8.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_valid_utf8.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -79,7 +79,7 @@ + register int ab; + register int c = *p; + if (c < 128) continue; +- if ((c & 0xc0) != 0xc0) return p - string; ++ if (c < 0xc0) return p - string; + ab = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */ + if (length < ab) return p - string; + length -= ab; +diff -ruN ../pcre.orig/pcrelib/pcre_version.c ./pcrelib/pcre_version.c +--- ../pcre.orig/pcrelib/pcre_version.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcre_version.c Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -49,16 +49,38 @@ + * Return version string * + *************************************************/ + ++/* These macros are the standard way of turning unquoted text into C strings. ++They allow macros like PCRE_MAJOR to be defined without quotes, which is ++convenient for user programs that want to test its value. */ ++ + #define STRING(a) # a + #define XSTRING(s) STRING(s) + ++/* A problem turned up with PCRE_PRERELEASE, which is defined empty for ++production releases. Originally, it was used naively in this code: ++ ++ return XSTRING(PCRE_MAJOR) ++ "." XSTRING(PCRE_MINOR) ++ XSTRING(PCRE_PRERELEASE) ++ " " XSTRING(PCRE_DATE); ++ ++However, when PCRE_PRERELEASE is empty, this leads to an attempted expansion of ++STRING(). The C standard states: "If (before argument substitution) any ++argument consists of no preprocessing tokens, the behavior is undefined." It ++turns out the gcc treats this case as a single empty string - which is what we ++really want - but Visual C grumbles about the lack of an argument for the ++macro. Unfortunately, both are within their rights. To cope with both ways of ++handling this, I had resort to some messy hackery that does a test at run time. ++I could find no way of detecting that a macro is defined as an empty string at ++pre-processor time. This hack uses a standard trick for avoiding calling ++the STRING macro with an empty argument when doing the test. */ ++ + PCRE_DATA_SCOPE const char * + pcre_version(void) + { +-return XSTRING(PCRE_MAJOR) +- "." XSTRING(PCRE_MINOR) +- XSTRING(PCRE_PRERELEASE) +- " " XSTRING(PCRE_DATE); ++return (XSTRING(Z PCRE_PRERELEASE)[1] == 0)? ++ XSTRING(PCRE_MAJOR.PCRE_MINOR PCRE_DATE) : ++ XSTRING(PCRE_MAJOR.PCRE_MINOR) XSTRING(PCRE_PRERELEASE PCRE_DATE); + } + + /* End of pcre_version.c */ +diff -ruN ../pcre.orig/pcrelib/pcrecpp.cc ./pcrelib/pcrecpp.cc +--- ../pcre.orig/pcrelib/pcrecpp.cc Wed Aug 30 22:00:22 2006 ++++ ./pcrelib/pcrecpp.cc Fri Feb 9 22:31:20 2007 +@@ -61,7 +61,7 @@ + // If the user doesn't ask for any options, we just use this one + static RE_Options default_options; + +-void RE::Init(const char* pat, const RE_Options* options) { ++void RE::Init(const string& pat, const RE_Options* options) { + pattern_ = pat; + if (options == NULL) { + options_ = default_options; +@@ -78,7 +78,7 @@ + // conservative in that it may treat some "simple" patterns + // as "complex" (e.g., if the vertical bar is in a character + // class or is escaped). But it seems good enough. +- if (strchr(pat, '|') == NULL) { ++ if (strchr(pat.c_str(), '|') == NULL) { + // Simple pattern: we can use position-based checks to perform + // fully anchored matches + re_full_ = re_partial_; +@@ -89,12 +89,18 @@ + } + } + +-RE::~RE() { ++void RE::Cleanup() { + if (re_full_ != NULL && re_full_ != re_partial_) (*pcre_free)(re_full_); + if (re_partial_ != NULL) (*pcre_free)(re_partial_); + if (error_ != &empty_string) delete error_; + } + ++ ++RE::~RE() { ++ Cleanup(); ++} ++ ++ + pcre* RE::Compile(Anchor anchor) { + // First, convert RE_Options into pcre options + int pcre_options = 0; +@@ -424,6 +430,34 @@ + return Rewrite(out, rewrite, text, vec, matches); + } + ++/*static*/ string RE::QuoteMeta(const StringPiece& unquoted) { ++ string result; ++ ++ // Escape any ascii character not in [A-Za-z_0-9]. ++ // ++ // Note that it's legal to escape a character even if it has no ++ // special meaning in a regular expression -- so this function does ++ // that. (This also makes it identical to the perl function of the ++ // same name; see `perldoc -f quotemeta`.) ++ for (int ii = 0; ii < unquoted.size(); ++ii) { ++ // Note that using 'isalnum' here raises the benchmark time from ++ // 32ns to 58ns: ++ if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') && ++ (unquoted[ii] < 'A' || unquoted[ii] > 'Z') && ++ (unquoted[ii] < '0' || unquoted[ii] > '9') && ++ unquoted[ii] != '_' && ++ // If this is the part of a UTF8 or Latin1 character, we need ++ // to copy this byte without escaping. Experimentally this is ++ // what works correctly with the regexp library. ++ !(unquoted[ii] & 128)) { ++ result += '\\'; ++ } ++ result += unquoted[ii]; ++ } ++ ++ return result; ++} ++ + /***** Actual matching and rewriting code *****/ + + int RE::TryMatch(const StringPiece& text, +@@ -809,14 +843,14 @@ + return parse_##name##_radix(str, n, dest, 0); \ + } + +-DEFINE_INTEGER_PARSERS(short); +-DEFINE_INTEGER_PARSERS(ushort); +-DEFINE_INTEGER_PARSERS(int); +-DEFINE_INTEGER_PARSERS(uint); +-DEFINE_INTEGER_PARSERS(long); +-DEFINE_INTEGER_PARSERS(ulong); +-DEFINE_INTEGER_PARSERS(longlong); +-DEFINE_INTEGER_PARSERS(ulonglong); ++DEFINE_INTEGER_PARSERS(short) /* */ ++DEFINE_INTEGER_PARSERS(ushort) /* */ ++DEFINE_INTEGER_PARSERS(int) /* Don't use semicolons after these */ ++DEFINE_INTEGER_PARSERS(uint) /* statements because they can cause */ ++DEFINE_INTEGER_PARSERS(long) /* compiler warnings if the checking */ ++DEFINE_INTEGER_PARSERS(ulong) /* level is turned up high enough. */ ++DEFINE_INTEGER_PARSERS(longlong) /* */ ++DEFINE_INTEGER_PARSERS(ulonglong) /* */ + + #undef DEFINE_INTEGER_PARSERS + +diff -ruN ../pcre.orig/pcrelib/pcrecpp.h ./pcrelib/pcrecpp.h +--- ../pcre.orig/pcrelib/pcrecpp.h Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/pcrecpp.h Fri Feb 9 22:31:20 2007 +@@ -112,6 +112,12 @@ + // T (where "bool T::ParseFrom(const char*, int)" exists) + // NULL (the corresponding matched sub-pattern is not copied) + // ++// CAVEAT: An optional sub-pattern that does not exist in the matched ++// string is assigned the empty string. Therefore, the following will ++// return false (because the empty string is not a valid number): ++// int number; ++// pcrecpp::RE::FullMatch("abc", "[a-z]+(\\d+)?", &number); ++// + // ----------------------------------------------------------------------- + // DO_MATCH + // +@@ -488,8 +494,25 @@ + // pass in a string or a "const char*" wherever an "RE" is expected. + RE(const char* pat) { Init(pat, NULL); } + RE(const char *pat, const RE_Options& option) { Init(pat, &option); } +- RE(const string& pat) { Init(pat.c_str(), NULL); } +- RE(const string& pat, const RE_Options& option) { Init(pat.c_str(), &option); } ++ RE(const string& pat) { Init(pat, NULL); } ++ RE(const string& pat, const RE_Options& option) { Init(pat, &option); } ++ ++ // Copy constructor & assignment - note that these are expensive ++ // because they recompile the expression. ++ RE(const RE& re) { Init(re.pattern_, &re.options_); } ++ const RE& operator=(const RE& re) { ++ if (this != &re) { ++ Cleanup(); ++ ++ // This is the code that originally came from Google ++ // Init(re.pattern_.c_str(), &re.options_); ++ ++ // This is the replacement from Ari Pollak ++ Init(re.pattern_, &re.options_); ++ } ++ return *this; ++ } ++ + + ~RE(); + +@@ -589,6 +612,15 @@ + const StringPiece &text, + string *out) const; + ++ // Escapes all potentially meaningful regexp characters in ++ // 'unquoted'. The returned string, used as a regular expression, ++ // will exactly match the original string. For example, ++ // 1.5-2.0? ++ // may become: ++ // 1\.5\-2\.0\? ++ static string QuoteMeta(const StringPiece& unquoted); ++ ++ + /***** Generic matching interface *****/ + + // Type of match (TODO: Should be restructured as part of RE_Options) +@@ -611,7 +643,8 @@ + + private: + +- void Init(const char* pattern, const RE_Options* options); ++ void Init(const string& pattern, const RE_Options* options); ++ void Cleanup(); + + // Match against "text", filling in "vec" (up to "vecsize" * 2/3) with + // pairs of integers for the beginning and end positions of matched +@@ -655,11 +688,6 @@ + pcre* re_full_; // For full matches + pcre* re_partial_; // For partial matches + const string* error_; // Error indicator (or points to empty string) +- +- // Don't allow the default copy or assignment constructors -- +- // they're expensive and too easy to do by accident. +- RE(const RE&); +- void operator=(const RE&); + }; + + } // namespace pcrecpp +diff -ruN ../pcre.orig/pcrelib/pcrecpp_unittest.cc ./pcrelib/pcrecpp_unittest.cc +--- ../pcre.orig/pcrelib/pcrecpp_unittest.cc Wed Aug 30 22:00:22 2006 ++++ ./pcrelib/pcrecpp_unittest.cc Fri Feb 9 22:31:20 2007 +@@ -1,4 +1,6 @@ +-// Copyright (c) 2005, Google Inc. ++// -*- coding: utf-8 -*- ++// ++// Copyright (c) 2005 - 2006, Google Inc. + // All rights reserved. + // + // Redistribution and use in source and binary forms, with or without +@@ -445,6 +447,80 @@ + CHECK(re4.FullMatch(text_bad) == false); + } + ++// A meta-quoted string, interpreted as a pattern, should always match ++// the original unquoted string. ++static void TestQuoteMeta(string unquoted, RE_Options options = RE_Options()) { ++ string quoted = RE::QuoteMeta(unquoted); ++ RE re(quoted, options); ++ CHECK(re.FullMatch(unquoted)); ++} ++ ++// A string containing meaningful regexp characters, which is then meta- ++// quoted, should not generally match a string the unquoted string does. ++static void NegativeTestQuoteMeta(string unquoted, string should_not_match, ++ RE_Options options = RE_Options()) { ++ string quoted = RE::QuoteMeta(unquoted); ++ RE re(quoted, options); ++ CHECK(!re.FullMatch(should_not_match)); ++} ++ ++// Tests that quoted meta characters match their original strings, ++// and that a few things that shouldn't match indeed do not. ++static void TestQuotaMetaSimple() { ++ TestQuoteMeta("foo"); ++ TestQuoteMeta("foo.bar"); ++ TestQuoteMeta("foo\\.bar"); ++ TestQuoteMeta("[1-9]"); ++ TestQuoteMeta("1.5-2.0?"); ++ TestQuoteMeta("\\d"); ++ TestQuoteMeta("Who doesn't like ice cream?"); ++ TestQuoteMeta("((a|b)c?d*e+[f-h]i)"); ++ TestQuoteMeta("((?!)xxx).*yyy"); ++ TestQuoteMeta("(["); ++} ++ ++static void TestQuoteMetaSimpleNegative() { ++ NegativeTestQuoteMeta("foo", "bar"); ++ NegativeTestQuoteMeta("...", "bar"); ++ NegativeTestQuoteMeta("\\.", "."); ++ NegativeTestQuoteMeta("\\.", ".."); ++ NegativeTestQuoteMeta("(a)", "a"); ++ NegativeTestQuoteMeta("(a|b)", "a"); ++ NegativeTestQuoteMeta("(a|b)", "(a)"); ++ NegativeTestQuoteMeta("(a|b)", "a|b"); ++ NegativeTestQuoteMeta("[0-9]", "0"); ++ NegativeTestQuoteMeta("[0-9]", "0-9"); ++ NegativeTestQuoteMeta("[0-9]", "[9]"); ++ NegativeTestQuoteMeta("((?!)xxx)", "xxx"); ++} ++ ++static void TestQuoteMetaLatin1() { ++ TestQuoteMeta("3\xb2 = 9"); ++} ++ ++static void TestQuoteMetaUtf8() { ++#ifdef SUPPORT_UTF8 ++ TestQuoteMeta("Pl\xc3\xa1\x63ido Domingo", pcrecpp::UTF8()); ++ TestQuoteMeta("xyz", pcrecpp::UTF8()); // No fancy utf8 ++ TestQuoteMeta("\xc2\xb0", pcrecpp::UTF8()); // 2-byte utf8 (degree symbol) ++ TestQuoteMeta("27\xc2\xb0 degrees", pcrecpp::UTF8()); // As a middle character ++ TestQuoteMeta("\xe2\x80\xb3", pcrecpp::UTF8()); // 3-byte utf8 (double prime) ++ TestQuoteMeta("\xf0\x9d\x85\x9f", pcrecpp::UTF8()); // 4-byte utf8 (music note) ++ TestQuoteMeta("27\xc2\xb0"); // Interpreted as Latin-1, but should still work ++ NegativeTestQuoteMeta("27\xc2\xb0", // 2-byte utf (degree symbol) ++ "27\\\xc2\\\xb0", ++ pcrecpp::UTF8()); ++#endif ++} ++ ++static void TestQuoteMetaAll() { ++ printf("Testing QuoteMeta\n"); ++ TestQuotaMetaSimple(); ++ TestQuoteMetaSimpleNegative(); ++ TestQuoteMetaLatin1(); ++ TestQuoteMetaUtf8(); ++} ++ + // + // Options tests contributed by + // Giuseppe Maxia, CTO, Stardata s.r.l. +@@ -667,6 +743,35 @@ + Test_all_options(); + } + ++static void TestConstructors() { ++ printf("Testing constructors\n"); ++ ++ RE_Options options; ++ options.set_dotall(true); ++ const char *str = "HELLO\n" "cruel\n" "world"; ++ ++ RE orig("HELLO.*world", options); ++ CHECK(orig.FullMatch(str)); ++ ++ RE copy1(orig); ++ CHECK(copy1.FullMatch(str)); ++ ++ RE copy2("not a match"); ++ CHECK(!copy2.FullMatch(str)); ++ copy2 = copy1; ++ CHECK(copy2.FullMatch(str)); ++ copy2 = orig; ++ CHECK(copy2.FullMatch(str)); ++ ++ // Make sure when we assign to ourselves, nothing bad happens ++ orig = orig; ++ copy1 = copy1; ++ copy2 = copy2; ++ CHECK(orig.FullMatch(str)); ++ CHECK(copy1.FullMatch(str)); ++ CHECK(copy2.FullMatch(str)); ++} ++ + int main(int argc, char** argv) { + // Treat any flag as --help + if (argc > 1 && argv[1][0] == '-') { +@@ -985,11 +1090,14 @@ + CHECK(RE("h.*o").PartialMatch("hello!")); + CHECK(RE("((((((((((((((((((((x))))))))))))))))))))").PartialMatch("x")); + ++ /***** other tests *****/ ++ + RadixTests(); + TestReplace(); + TestExtract(); + TestConsume(); + TestFindAndConsume(); ++ TestQuoteMetaAll(); + TestMatchNumberPeculiarity(); + + // Check the pattern() accessor +@@ -1108,6 +1216,9 @@ + if (getenv("VERBOSE_TEST") != NULL) + VERBOSE_TEST = true; + TestOptions(); ++ ++ // Test the constructors ++ TestConstructors(); + + // Done + printf("OK\n"); +diff -ruN ../pcre.orig/pcrelib/pcregrep.c ./pcrelib/pcregrep.c +--- ../pcre.orig/pcrelib/pcregrep.c Wed Jan 3 21:08:37 2007 ++++ ./pcrelib/pcregrep.c Tue Feb 27 04:31:14 2007 +@@ -6,7 +6,7 @@ + its pattern matching. On a Unix or Win32 system it can recurse into + directories. + +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -56,7 +56,7 @@ + + typedef int BOOL; + +-#define VERSION "4.3 01-Jun-2006" ++#define VERSION "4.4 29-Nov-2006" + #define MAX_PATTERN_COUNT 100 + + #if BUFSIZ > 8192 +@@ -65,7 +65,6 @@ + #define MBUFTHIRD 8192 + #endif + +- + /* Values for the "filenames" variable, which specifies options for file name + output. The order is important; it is assumed that a file name is wanted for + all values greater than FN_DEFAULT. */ +@@ -83,6 +82,10 @@ + #define PO_LINE_MATCH 0x0002 + #define PO_FIXED_STRINGS 0x0004 + ++/* Line ending types */ ++ ++enum { EL_LF, EL_CR, EL_CRLF, EL_ANY }; ++ + + + /************************************************* +@@ -100,8 +103,7 @@ + static const char *jfriedl_postfix = ""; + #endif + +-static int endlinebyte = '\n'; /* Last byte of endline sequence */ +-static int endlineextra = 0; /* Extra bytes for endline sequence */ ++static int endlinetype; + + static char *colour_string = (char *)"1;31"; + static char *colour_option = NULL; +@@ -142,6 +144,7 @@ + static BOOL only_matching = FALSE; + static BOOL quiet = FALSE; + static BOOL silent = FALSE; ++static BOOL utf8 = FALSE; + + /* Structure for options and list of them */ + +@@ -219,6 +222,16 @@ + static const char *suffix[] = { + "", "\\b", ")$", ")$", "\\E", "\\E\\b", "\\E)$", "\\E)$" }; + ++/* UTF-8 tables - used only when the newline setting is "all". */ ++ ++const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; ++ ++const char utf8_table4[] = { ++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, ++ 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; ++ + + + /************************************************* +@@ -471,6 +484,216 @@ + + + /************************************************* ++* Find end of line * ++*************************************************/ ++ ++/* The length of the endline sequence that is found is set via lenptr. This may ++be zero at the very end of the file if there is no line-ending sequence there. ++ ++Arguments: ++ p current position in line ++ endptr end of available data ++ lenptr where to put the length of the eol sequence ++ ++Returns: pointer to the last byte of the line ++*/ ++ ++static char * ++end_of_line(char *p, char *endptr, int *lenptr) ++{ ++switch(endlinetype) ++ { ++ default: /* Just in case */ ++ case EL_LF: ++ while (p < endptr && *p != '\n') p++; ++ if (p < endptr) ++ { ++ *lenptr = 1; ++ return p + 1; ++ } ++ *lenptr = 0; ++ return endptr; ++ ++ case EL_CR: ++ while (p < endptr && *p != '\r') p++; ++ if (p < endptr) ++ { ++ *lenptr = 1; ++ return p + 1; ++ } ++ *lenptr = 0; ++ return endptr; ++ ++ case EL_CRLF: ++ for (;;) ++ { ++ while (p < endptr && *p != '\r') p++; ++ if (++p >= endptr) ++ { ++ *lenptr = 0; ++ return endptr; ++ } ++ if (*p == '\n') ++ { ++ *lenptr = 2; ++ return p + 1; ++ } ++ } ++ break; ++ ++ case EL_ANY: ++ while (p < endptr) ++ { ++ int extra = 0; ++ register int c = *((unsigned char *)p); ++ ++ if (utf8 && c >= 0xc0) ++ { ++ int gcii, gcss; ++ extra = utf8_table4[c & 0x3f]; /* Number of additional bytes */ ++ gcss = 6*extra; ++ c = (c & utf8_table3[extra]) << gcss; ++ for (gcii = 1; gcii <= extra; gcii++) ++ { ++ gcss -= 6; ++ c |= (p[gcii] & 0x3f) << gcss; ++ } ++ } ++ ++ p += 1 + extra; ++ ++ switch (c) ++ { ++ case 0x0a: /* LF */ ++ case 0x0b: /* VT */ ++ case 0x0c: /* FF */ ++ *lenptr = 1; ++ return p; ++ ++ case 0x0d: /* CR */ ++ if (p < endptr && *p == 0x0a) ++ { ++ *lenptr = 2; ++ p++; ++ } ++ else *lenptr = 1; ++ return p; ++ ++ case 0x85: /* NEL */ ++ *lenptr = utf8? 2 : 1; ++ return p; ++ ++ case 0x2028: /* LS */ ++ case 0x2029: /* PS */ ++ *lenptr = 3; ++ return p; ++ ++ default: ++ break; ++ } ++ } /* End of loop for ANY case */ ++ ++ *lenptr = 0; /* Must have hit the end */ ++ return endptr; ++ } /* End of overall switch */ ++} ++ ++ ++ ++/************************************************* ++* Find start of previous line * ++*************************************************/ ++ ++/* This is called when looking back for before lines to print. ++ ++Arguments: ++ p start of the subsequent line ++ startptr start of available data ++ ++Returns: pointer to the start of the previous line ++*/ ++ ++static char * ++previous_line(char *p, char *startptr) ++{ ++switch(endlinetype) ++ { ++ default: /* Just in case */ ++ case EL_LF: ++ p--; ++ while (p > startptr && p[-1] != '\n') p--; ++ return p; ++ ++ case EL_CR: ++ p--; ++ while (p > startptr && p[-1] != '\n') p--; ++ return p; ++ ++ case EL_CRLF: ++ for (;;) ++ { ++ p -= 2; ++ while (p > startptr && p[-1] != '\n') p--; ++ if (p <= startptr + 1 || p[-2] == '\r') return p; ++ } ++ return p; /* But control should never get here */ ++ ++ case EL_ANY: ++ if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--; ++ if (utf8) while ((*p & 0xc0) == 0x80) p--; ++ ++ while (p > startptr) ++ { ++ register int c; ++ char *pp = p - 1; ++ ++ if (utf8) ++ { ++ int extra = 0; ++ while ((*pp & 0xc0) == 0x80) pp--; ++ c = *((unsigned char *)pp); ++ if (c >= 0xc0) ++ { ++ int gcii, gcss; ++ extra = utf8_table4[c & 0x3f]; /* Number of additional bytes */ ++ gcss = 6*extra; ++ c = (c & utf8_table3[extra]) << gcss; ++ for (gcii = 1; gcii <= extra; gcii++) ++ { ++ gcss -= 6; ++ c |= (pp[gcii] & 0x3f) << gcss; ++ } ++ } ++ } ++ else c = *((unsigned char *)pp); ++ ++ switch (c) ++ { ++ case 0x0a: /* LF */ ++ case 0x0b: /* VT */ ++ case 0x0c: /* FF */ ++ case 0x0d: /* CR */ ++ case 0x85: /* NEL */ ++ case 0x2028: /* LS */ ++ case 0x2029: /* PS */ ++ return p; ++ ++ default: ++ break; ++ } ++ ++ p = pp; /* Back one character */ ++ } /* End of loop for ANY case */ ++ ++ return startptr; /* Hit start of data */ ++ } /* End of overall switch */ ++} ++ ++ ++ ++ ++ ++/************************************************* + * Print the previous "after" lines * + *************************************************/ + +@@ -495,13 +718,13 @@ + int count = 0; + while (lastmatchrestart < endptr && count++ < after_context) + { ++ int ellength; + char *pp = lastmatchrestart; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%d-", lastmatchnumber++); +- while (*pp != endlinebyte) pp++; +- fwrite(lastmatchrestart, 1, pp - lastmatchrestart + (1 + endlineextra), +- stdout); +- lastmatchrestart = pp + 1; ++ pp = end_of_line(pp, endptr, &ellength); ++ fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout); ++ lastmatchrestart = pp; + } + hyphenpending = TRUE; + } +@@ -558,7 +781,7 @@ + + while (ptr < endptr) + { +- int i; ++ int i, endlinelength; + int mrc = 0; + BOOL match = FALSE; + char *t = ptr; +@@ -571,11 +794,10 @@ + line. In multiline mode the PCRE_FIRSTLINE option is used for compiling, so + that any match is constrained to be in the first line. */ + +- linelength = 0; +- while (t < endptr && *t++ != endlinebyte) linelength++; ++ t = end_of_line(t, endptr, &endlinelength); ++ linelength = t - ptr - endlinelength; + length = multiline? endptr - ptr : linelength; + +- + /* Extra processing for Jeffrey Friedl's debugging. */ + + #ifdef JFRIEDL_DEBUG +@@ -706,13 +928,13 @@ + + if (after_context > 0 && lastmatchnumber > 0) + { ++ int ellength; + int linecount = 0; + char *p = lastmatchrestart; + + while (p < ptr && linecount < after_context) + { +- while (*p != endlinebyte) p++; +- p++; ++ p = end_of_line(p, ptr, &ellength); + linecount++; + } + +@@ -725,10 +947,9 @@ + char *pp = lastmatchrestart; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%d-", lastmatchnumber++); +- while (*pp != endlinebyte) pp++; +- fwrite(lastmatchrestart, 1, pp - lastmatchrestart + +- (1 + endlineextra), stdout); +- lastmatchrestart = pp + 1; ++ pp = end_of_line(pp, endptr, &ellength); ++ fwrite(lastmatchrestart, 1, pp - lastmatchrestart, stdout); ++ lastmatchrestart = pp; + } + if (lastmatchrestart != ptr) hyphenpending = TRUE; + } +@@ -754,8 +975,7 @@ + linecount < before_context) + { + linecount++; +- p--; +- while (p > buffer && p[-1] != endlinebyte) p--; ++ p = previous_line(p, buffer); + } + + if (lastmatchnumber > 0 && p > lastmatchrestart && !hyphenprinted) +@@ -763,12 +983,13 @@ + + while (p < ptr) + { ++ int ellength; + char *pp = p; + if (printname != NULL) fprintf(stdout, "%s-", printname); + if (number) fprintf(stdout, "%d-", linenumber - linecount--); +- while (*pp != endlinebyte) pp++; +- fwrite(p, 1, pp - p + (1 + endlineextra), stdout); +- p = pp + 1; ++ pp = end_of_line(pp, endptr, &ellength); ++ fwrite(p, 1, pp - p, stdout); ++ p = pp; + } + } + +@@ -788,11 +1009,16 @@ + + if (multiline) + { ++ int ellength; + char *endmatch = ptr + offsets[1]; + t = ptr; +- while (t < endmatch) { if (*t++ == endlinebyte) linenumber++; } +- while (endmatch < endptr && *endmatch != endlinebyte) endmatch++; +- linelength = endmatch - ptr; ++ while (t < endmatch) ++ { ++ t = end_of_line(t, endptr, &ellength); ++ if (t <= endmatch) linenumber++; else break; ++ } ++ endmatch = end_of_line(endmatch, endptr, &ellength); ++ linelength = endmatch - ptr - ellength; + } + + /*** NOTE: Use only fwrite() to output the data line, so that binary +@@ -824,9 +1050,7 @@ + fprintf(stdout, "%c[00m", 0x1b); + fwrite(ptr + offsets[1], 1, linelength - offsets[1], stdout); + } +- else fwrite(ptr, 1, linelength, stdout); +- +- fprintf(stdout, "\n"); ++ else fwrite(ptr, 1, linelength + endlinelength, stdout); + } + + /* End of doing what has to be done for a match */ +@@ -836,13 +1060,13 @@ + /* Remember where the last match happened for after_context. We remember + where we are about to restart, and that line's number. */ + +- lastmatchrestart = ptr + linelength + 1; ++ lastmatchrestart = ptr + linelength + endlinelength; + lastmatchnumber = linenumber + 1; + } + + /* Advance to after the newline and increment the line number. */ + +- ptr += linelength + 1; ++ ptr += linelength + endlinelength; + linenumber++; + + /* If we haven't yet reached the end of the file (the buffer is full), and +@@ -964,8 +1188,7 @@ + while ((nextfile = readdirectory(dir)) != NULL) + { + int frc, blen; +- sprintf(buffer, "%.512s%c%.128s", pathname, sep, nextfile); +- blen = strlen(buffer); ++ blen = slprintf(buffer, sizeof(buffer), "%.512s%c%.128s", pathname, sep, nextfile); + + if (exclude_compiled != NULL && + pcre_exec(exclude_compiled, NULL, buffer, blen, 0, 0, NULL, 0) >= 0) +@@ -1057,7 +1280,7 @@ + { + int n; + char s[4]; +- if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, " "); ++ if (op->one_char > 0) snprintf(s, sizeof(s), "-%c,", op->one_char); else strcpy(s, " "); + printf(" %s --%s%n", s, op->long_name, &n); + n = 30 - n; + if (n < 1) n = 1; +@@ -1098,7 +1321,7 @@ + case 'q': quiet = TRUE; break; + case 'r': dee_action = dee_RECURSE; break; + case 's': silent = TRUE; break; +- case 'u': options |= PCRE_UTF8; break; ++ case 'u': options |= PCRE_UTF8; utf8 = TRUE; break; + case 'v': invert = TRUE; break; + case 'w': process_options |= PO_WORD_MATCH; break; + case 'x': process_options |= PO_LINE_MATCH; break; +@@ -1131,7 +1354,7 @@ + { + static char buffer[8]; + char *p = buffer; +-sprintf(p, "%d", n); ++snprintf(p, sizeof(buffer), "%d", n); + while (*p != 0) p++; + switch (n%10) + { +@@ -1177,7 +1400,7 @@ + return FALSE; + } + +-sprintf(buffer, "%s%.*s%s", prefix[process_options], MBUFTHIRD, pattern, ++snprintf(buffer, sizeof(buffer), "%s%.*s%s", prefix[process_options], MBUFTHIRD, pattern, + suffix[process_options]); + pattern_list[pattern_count] = + pcre_compile(buffer, options, &error, &errptr, pcretables); +@@ -1231,14 +1454,16 @@ + { + if ((process_options & PO_FIXED_STRINGS) != 0) + { ++ char *eop = pattern + strlen(pattern); + char buffer[MBUFTHIRD]; + for(;;) + { +- char *p = strchr(pattern, endlinebyte); +- if (p == NULL) ++ int ellength; ++ char *p = end_of_line(pattern, eop, &ellength); ++ if (ellength == 0) + return compile_single_pattern(pattern, options, filename, count); +- sprintf(buffer, "%.*s", p - pattern - endlineextra, pattern); +- pattern = p + 1; ++ snprintf(buffer, sizeof(buffer), "%.*s", p - pattern - ellength, pattern); ++ pattern = p; + if (!compile_single_pattern(buffer, options, filename, count)) + return FALSE; + } +@@ -1267,7 +1492,9 @@ + const char *locale_from = "--locale"; + const char *error; + +-/* Set the default line ending value from the default in the PCRE library. */ ++/* Set the default line ending value from the default in the PCRE library; ++"lf", "cr", "crlf", and "any" are supported. Anything else is treated as "lf". ++*/ + + (void)pcre_config(PCRE_CONFIG_NEWLINE, &i); + switch(i) +@@ -1275,6 +1502,7 @@ + default: newline = (char *)"lf"; break; + case '\r': newline = (char *)"cr"; break; + case ('\r' << 8) | '\n': newline = (char *)"crlf"; break; ++ case -1: newline = (char *)"any"; break; + } + + /* Process the options */ +@@ -1350,8 +1578,8 @@ + char buff1[24]; + char buff2[24]; + int baselen = opbra - op->long_name; +- sprintf(buff1, "%.*s", baselen, op->long_name); +- sprintf(buff2, "%s%.*s", buff1, strlen(op->long_name) - baselen - 2, ++ snprintf(buff1, sizeof(buff1), "%.*s", baselen, op->long_name); ++ snprintf(buff2, sizeof(buff2), "%s%.*s", buff1, strlen(op->long_name) - baselen - 2, + opbra + 1); + if (strcmp(arg, buff1) == 0 || strcmp(arg, buff2) == 0) + break; +@@ -1565,16 +1793,22 @@ + if (strcmp(newline, "cr") == 0 || strcmp(newline, "CR") == 0) + { + pcre_options |= PCRE_NEWLINE_CR; +- endlinebyte = '\r'; ++ endlinetype = EL_CR; + } + else if (strcmp(newline, "lf") == 0 || strcmp(newline, "LF") == 0) + { + pcre_options |= PCRE_NEWLINE_LF; ++ endlinetype = EL_LF; + } + else if (strcmp(newline, "crlf") == 0 || strcmp(newline, "CRLF") == 0) + { + pcre_options |= PCRE_NEWLINE_CRLF; +- endlineextra = 1; ++ endlinetype = EL_CRLF; ++ } ++else if (strcmp(newline, "any") == 0 || strcmp(newline, "ANY") == 0) ++ { ++ pcre_options |= PCRE_NEWLINE_ANY; ++ endlinetype = EL_ANY; + } + else + { +@@ -1700,7 +1934,7 @@ + if (error != NULL) + { + char s[16]; +- if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j); ++ if (pattern_count == 1) s[0] = 0; else snprintf(s, sizeof(s), " number %d", j); + fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error); + return 2; + } +diff -ruN ../pcre.orig/pcrelib/pcreposix.c ./pcrelib/pcreposix.c +--- ../pcre.orig/pcrelib/pcreposix.c Mon Jan 1 10:36:04 2007 ++++ ./pcrelib/pcreposix.c Sat Feb 24 04:30:55 2007 +@@ -6,7 +6,7 @@ + and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel +- Copyright (c) 1997-2007 University of Cambridge ++ Copyright (c) 1997-2006 University of Cambridge + + ----------------------------------------------------------------------------- + Redistribution and use in source and binary forms, with or without +@@ -78,7 +78,7 @@ + REG_BADPAT, /* unrecognized character after (?< */ + REG_BADPAT, /* lookbehind assertion is not fixed length */ + REG_BADPAT, /* malformed number or name after (?( */ +- REG_BADPAT, /* conditional group containe more than two branches */ ++ REG_BADPAT, /* conditional group contains more than two branches */ + REG_BADPAT, /* assertion expected after (?( */ + REG_BADPAT, /* (?R or (?digits must be followed by ) */ + REG_ECTYPE, /* unknown POSIX class name */ +@@ -93,7 +93,7 @@ + REG_BADPAT, /* closing ) for (?C expected */ + REG_BADPAT, /* recursive call could loop indefinitely */ + REG_BADPAT, /* unrecognized character after (?P */ +- REG_BADPAT, /* syntax error after (?P */ ++ REG_BADPAT, /* syntax error in subpattern name (missing terminator) */ + REG_BADPAT, /* two named subpatterns have the same name */ + REG_BADPAT, /* invalid UTF-8 string */ + REG_BADPAT, /* support for \P, \p, and \X has not been compiled */ +@@ -102,7 +102,13 @@ + REG_BADPAT, /* subpattern name is too long (maximum 32 characters) */ + REG_BADPAT, /* too many named subpatterns (maximum 10,000) */ + REG_BADPAT, /* repeated subpattern is too long */ +- REG_BADPAT /* octal value is greater than \377 (not in UTF-8 mode) */ ++ REG_BADPAT, /* octal value is greater than \377 (not in UTF-8 mode) */ ++ REG_BADPAT, /* internal error: overran compiling workspace */ ++ REG_BADPAT, /* internal error: previously-checked referenced subpattern not found */ ++ REG_BADPAT, /* DEFINE group contains more than one branch */ ++ REG_BADPAT, /* repeating a DEFINE group is not allowed */ ++ REG_INVARG, /* inconsistent NEWLINE options */ ++ REG_BADPAT /* \g is not followed followed by an (optionally braced) non-zero number */ + }; + + /* Table of texts corresponding to POSIX error codes */ +@@ -152,7 +158,7 @@ + if (errbuf_size > 0) + { + if (addlength > 0 && errbuf_size >= length + addlength) +- sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset); ++ snprintf(errbuf, errbuf_size, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset); + else + { + strncpy(errbuf, message, errbuf_size - 1); +diff -ruN ../pcre.orig/pcrelib/pcretest.c ./pcrelib/pcretest.c +--- ../pcre.orig/pcrelib/pcretest.c Wed Aug 30 22:00:22 2006 ++++ ./pcrelib/pcretest.c Fri Feb 9 22:31:20 2007 +@@ -44,10 +44,29 @@ + #include <locale.h> + #include <errno.h> + +-#ifndef _WIN32 +-#include <sys/resource.h> ++ ++/* A number of things vary for Windows builds. Originally, pcretest opened its ++input and output without "b"; then I was told that "b" was needed in some ++environments, so it was added for release 5.0 to both the input and output. (It ++makes no difference on Unix-like systems.) Later I was told that it is wrong ++for the input on Windows. I've now abstracted the modes into two macros that ++are set here, to make it easier to fiddle with them, and removed "b" from the ++input mode under Windows. */ ++ ++#if defined(_WIN32) || defined(WIN32) ++#include <io.h> /* For _setmode() */ ++#include <fcntl.h> /* For _O_BINARY */ ++#define INPUT_MODE "r" ++#define OUTPUT_MODE "wb" ++ ++#else ++#include <sys/time.h> /* These two includes are needed */ ++#include <sys/resource.h> /* for setrlimit(). */ ++#define INPUT_MODE "rb" ++#define OUTPUT_MODE "wb" + #endif + ++ + #define PCRE_SPY /* For Win32 build, import data, not export */ + + /* We include pcre_internal.h because we need the internal info for displaying +@@ -74,10 +93,18 @@ + + /* We also need the pcre_printint() function for printing out compiled + patterns. This function is in a separate file so that it can be included in +-pcre_compile.c when that module is compiled with debugging enabled. */ ++pcre_compile.c when that module is compiled with debugging enabled. ++ ++The definition of the macro PRINTABLE, which determines whether to print an ++output character as-is or as a hex value when showing compiled patterns, is ++contained in this file. We uses it here also, in cases when the locale has not ++been explicitly changed, so as to get consistent output from systems that ++differ in their output from isprint() even in the "C" locale. */ + + #include "pcre_printint.src" + ++#define PRINTHEX(c) (locale_set? isprint(c) : PRINTABLE(c)) ++ + + /* It is possible to compile this test program without including support for + testing the POSIX interface, though this is not available via the standard +@@ -103,6 +130,8 @@ + #endif + #endif + ++/* This is the default loop count for timing. */ ++ + #define LOOPREPEAT 500000 + + /* Static variables */ +@@ -114,6 +143,7 @@ + static int callout_fail_count; + static int callout_fail_id; + static int first_callout; ++static int locale_set = 0; + static int show_malloc; + static int use_utf8; + static size_t gotten_store; +@@ -157,6 +187,7 @@ + for (;;) + { + int rlen = buffer_size - (here - buffer); ++ + if (rlen > 1000) + { + int dlen; +@@ -213,7 +244,7 @@ + + /* We don't use strtoul() because SunOS4 doesn't have it. Rather than mess + around with conditional compilation, just do the job by hand. It is only used +-for unpicking the -o argument, so just keep it simple. ++for unpicking arguments, so just keep it simple. + + Arguments: + str string to be converted +@@ -311,6 +342,8 @@ + Returns: number of characters placed in the buffer + */ + ++#if !defined NOUTF8 ++ + static int + ord2utf8(int cvalue, uschar *utf8bytes) + { +@@ -327,6 +360,8 @@ + return i + 1; + } + ++#endif ++ + + + /************************************************* +@@ -353,16 +388,19 @@ + { + length -= rc - 1; + p += rc; +- if (c < 256 && isprint(c)) ++ if (PRINTHEX(c)) + { + if (f != NULL) fprintf(f, "%c", c); + yield++; + } + else + { +- int n; +- if (f != NULL) fprintf(f, "\\x{%02x}%n", c, &n); +- yield += n; ++ int n = 4; ++ if (f != NULL) fprintf(f, "\\x{%02x}", c); ++ yield += (n <= 0x000000ff)? 2 : ++ (n <= 0x00000fff)? 3 : ++ (n <= 0x0000ffff)? 4 : ++ (n <= 0x000fffff)? 5 : 6; + } + continue; + } +@@ -371,7 +409,8 @@ + + /* Not UTF-8, or malformed UTF-8 */ + +- if (isprint(c = *(p++))) ++ c = *p++; ++ if (PRINTHEX(c)) + { + if (f != NULL) fprintf(f, "%c", c); + yield++; +@@ -614,7 +653,7 @@ + *************************************************/ + + /* This is used both at compile and run-time to check for <xxx> escapes, where +-xxx is LF, CR, or CRLF. Print a message and return 0 if there is no match. ++xxx is LF, CR, CRLF, or ANY. Print a message and return 0 if there is no match. + + Arguments: + p points after the leading '<' +@@ -629,6 +668,7 @@ + if (strncmp((char *)p, "cr>", 3) == 0) return PCRE_NEWLINE_CR; + if (strncmp((char *)p, "lf>", 3) == 0) return PCRE_NEWLINE_LF; + if (strncmp((char *)p, "crlf>", 5) == 0) return PCRE_NEWLINE_CRLF; ++if (strncmp((char *)p, "any>", 4) == 0) return PCRE_NEWLINE_ANY; + fprintf(f, "Unknown newline type at: <%s\n", p); + return 0; + } +@@ -636,6 +676,38 @@ + + + /************************************************* ++* Usage function * ++*************************************************/ ++ ++static void ++usage(void) ++{ ++printf("Usage: pcretest [options] [<input> [<output>]]\n"); ++printf(" -b show compiled code (bytecode)\n"); ++printf(" -C show PCRE compile-time options and exit\n"); ++printf(" -d debug: show compiled code and information (-b and -i)\n"); ++#if !defined NODFA ++printf(" -dfa force DFA matching for all subjects\n"); ++#endif ++printf(" -help show usage information\n"); ++printf(" -i show information about compiled patterns\n" ++ " -m output memory used information\n" ++ " -o <n> set size of offsets vector to <n>\n"); ++#if !defined NOPOSIX ++printf(" -p use POSIX interface\n"); ++#endif ++printf(" -q quiet: do not output PCRE version number at start\n"); ++printf(" -S <n> set stack size to <n> megabytes\n"); ++printf(" -s output store (memory) used information\n" ++ " -t time compilation and execution\n"); ++printf(" -t <n> time compilation and execution, repeating <n> times\n"); ++printf(" -tm time execution (matching) only\n"); ++printf(" -tm <n> time execution (matching) only, repeating <n> times\n"); ++} ++ ++ ++ ++/************************************************* + * Main Program * + *************************************************/ + +@@ -650,6 +722,7 @@ + int study_options = 0; + int op = 1; + int timeit = 0; ++int timeitm = 0; + int showinfo = 0; + int showstore = 0; + int quiet = 0; +@@ -681,16 +754,19 @@ + dbuffer = (unsigned char *)malloc(buffer_size); + pbuffer = (unsigned char *)malloc(buffer_size); + +-/* The outfile variable is static so that new_malloc can use it. The _setmode() +-stuff is some magic that I don't understand, but which apparently does good +-things in Windows. It's related to line terminations. */ +- +-#if defined(_WIN32) || defined(WIN32) +-_setmode( _fileno( stdout ), 0x8000 ); +-#endif /* defined(_WIN32) || defined(WIN32) */ ++/* The outfile variable is static so that new_malloc can use it. */ + + outfile = stdout; + ++/* The following _setmode() stuff is some Windows magic that tells its runtime ++library to translate CRLF into a single LF character. At least, that's what ++I've been told: never having used Windows I take this all on trust. Originally ++it set 0x8000, but then I was advised that _O_BINARY was better. */ ++ ++#if defined(_WIN32) || defined(WIN32) ++_setmode( _fileno( stdout ), _O_BINARY ); ++#endif ++ + /* Scan options */ + + while (argc > 1 && argv[op][0] == '-') +@@ -699,8 +775,8 @@ + + if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0) + showstore = 1; +- else if (strcmp(argv[op], "-t") == 0) timeit = 1; + else if (strcmp(argv[op], "-q") == 0) quiet = 1; ++ else if (strcmp(argv[op], "-b") == 0) debug = 1; + else if (strcmp(argv[op], "-i") == 0) showinfo = 1; + else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1; + #if !defined NODFA +@@ -713,11 +789,25 @@ + op++; + argc--; + } ++ else if (strcmp(argv[op], "-t") == 0 || strcmp(argv[op], "-tm") == 0) ++ { ++ int both = argv[op][2] == 0; ++ int temp; ++ if (argc > 2 && (temp = get_value((unsigned char *)argv[op+1], &endptr), ++ *endptr == 0)) ++ { ++ timeitm = temp; ++ op++; ++ argc--; ++ } ++ else timeitm = LOOPREPEAT; ++ if (both) timeit = timeitm; ++ } + else if (strcmp(argv[op], "-S") == 0 && argc > 2 && + ((stack_size = get_value((unsigned char *)argv[op+1], &endptr)), + *endptr == 0)) + { +-#ifdef _WIN32 ++#if defined(_WIN32) || defined(WIN32) + printf("PCRE: -S not supported on this OS\n"); + exit(1); + #else +@@ -749,7 +839,8 @@ + printf(" %sUnicode properties support\n", rc? "" : "No "); + (void)pcre_config(PCRE_CONFIG_NEWLINE, &rc); + printf(" Newline sequence is %s\n", (rc == '\r')? "CR" : +- (rc == '\n')? "LF" : "CRLF"); ++ (rc == '\n')? "LF" : (rc == ('\r'<<8 | '\n'))? "CRLF" : ++ (rc == -1)? "ANY" : "???"); + (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc); + printf(" Internal link size = %d\n", rc); + (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc); +@@ -762,24 +853,16 @@ + printf(" Match recursion uses %s\n", rc? "stack" : "heap"); + exit(0); + } ++ else if (strcmp(argv[op], "-help") == 0 || ++ strcmp(argv[op], "--help") == 0) ++ { ++ usage(); ++ goto EXIT; ++ } + else + { + printf("** Unknown or malformed option %s\n", argv[op]); +- printf("Usage: pcretest [options] [<input> [<output>]]\n"); +- printf(" -C show PCRE compile-time options and exit\n"); +- printf(" -d debug: show compiled code; implies -i\n"); +-#if !defined NODFA +- printf(" -dfa force DFA matching for all subjects\n"); +-#endif +- printf(" -i show information about compiled pattern\n" +- " -m output memory used information\n" +- " -o <n> set size of offsets vector to <n>\n"); +-#if !defined NOPOSIX +- printf(" -p use POSIX interface\n"); +-#endif +- printf(" -S <n> set stack size to <n> megabytes\n"); +- printf(" -s output store (memory) used information\n" +- " -t time compilation and execution\n"); ++ usage(); + yield = 1; + goto EXIT; + } +@@ -803,7 +886,7 @@ + + if (argc > 1) + { +- infile = fopen(argv[op], "rb"); ++ infile = fopen(argv[op], INPUT_MODE); + if (infile == NULL) + { + printf("** Failed to open %s\n", argv[op]); +@@ -814,7 +897,7 @@ + + if (argc > 2) + { +- outfile = fopen(argv[op+1], "wb"); ++ outfile = fopen(argv[op+1], OUTPUT_MODE); + if (outfile == NULL) + { + printf("** Failed to open %s\n", argv[op+1]); +@@ -859,7 +942,7 @@ + int do_showinfo = showinfo; + int do_showrest = 0; + int do_flip = 0; +- int erroroffset, len, delimiter; ++ int erroroffset, len, delimiter, poffset; + + use_utf8 = 0; + +@@ -969,6 +1052,7 @@ + } + + pp = p; ++ poffset = p - buffer; + + for(;;) + { +@@ -989,6 +1073,11 @@ + if (infile != stdin) fprintf(outfile, "%s", (char *)pp); + } + ++ /* The buffer may have moved while being extended; reset the start of data ++ pointer to the correct relative point in the buffer. */ ++ ++ p = buffer + poffset; ++ + /* If the first character after the delimiter is backslash, make + the pattern end with backslash. This is purely to provide a way + of testing for the error message when a pattern ends with backslash. */ +@@ -1020,6 +1109,7 @@ + + case '+': do_showrest = 1; break; + case 'A': options |= PCRE_ANCHORED; break; ++ case 'B': do_debug = 1; break; + case 'C': options |= PCRE_AUTO_CALLOUT; break; + case 'D': do_debug = do_showinfo = 1; break; + case 'E': options |= PCRE_DOLLAR_ENDONLY; break; +@@ -1042,14 +1132,16 @@ + + case 'L': + ppp = pp; +- /* The '\r' test here is so that it works on Windows */ +- while (*ppp != '\n' && *ppp != '\r' && *ppp != ' ') ppp++; ++ /* The '\r' test here is so that it works on Windows. */ ++ /* The '0' test is just in case this is an unterminated line. */ ++ while (*ppp != 0 && *ppp != '\n' && *ppp != '\r' && *ppp != ' ') ppp++; + *ppp = 0; + if (setlocale(LC_CTYPE, (const char *)pp) == NULL) + { + fprintf(outfile, "** Failed to set locale \"%s\"\n", pp); + goto SKIP_DATA; + } ++ locale_set = 1; + tables = pcre_maketables(); + pp = ppp; + break; +@@ -1116,19 +1208,19 @@ + #endif /* !defined NOPOSIX */ + + { +- if (timeit) ++ if (timeit > 0) + { + register int i; + clock_t time_taken; + clock_t start_time = clock(); +- for (i = 0; i < LOOPREPEAT; i++) ++ for (i = 0; i < timeit; i++) + { + re = pcre_compile((char *)p, options, &error, &erroroffset, tables); + if (re != NULL) free(re); + } + time_taken = clock() - start_time; +- fprintf(outfile, "Compile time %.3f milliseconds\n", +- (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / ++ fprintf(outfile, "Compile time %.4f milliseconds\n", ++ (((double)time_taken * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + } + +@@ -1180,17 +1272,17 @@ + + if (do_study) + { +- if (timeit) ++ if (timeit > 0) + { + register int i; + clock_t time_taken; + clock_t start_time = clock(); +- for (i = 0; i < LOOPREPEAT; i++) ++ for (i = 0; i < timeit; i++) + extra = pcre_study(re, study_options, &error); + time_taken = clock() - start_time; + if (extra != NULL) free(extra); +- fprintf(outfile, " Study time %.3f milliseconds\n", +- (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / ++ fprintf(outfile, " Study time %.4f milliseconds\n", ++ (((double)time_taken * 1000.0) / (double)timeit) / + (double)CLOCKS_PER_SEC); + } + extra = pcre_study(re, study_options, &error); +@@ -1233,6 +1325,12 @@ + + SHOW_INFO: + ++ if (do_debug) ++ { ++ fprintf(outfile, "------------------------------------------------------------------\n"); ++ pcre_printint(re, outfile); ++ } ++ + if (do_showinfo) + { + unsigned long int get_options, all_options; +@@ -1243,12 +1341,6 @@ + int nameentrysize, namecount; + const uschar *nametable; + +- if (do_debug) +- { +- fprintf(outfile, "------------------------------------------------------------------\n"); +- pcre_printint(re, outfile); +- } +- + new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options); + new_info(re, NULL, PCRE_INFO_SIZE, &size); + new_info(re, NULL, PCRE_INFO_CAPTURECOUNT, &count); +@@ -1327,7 +1419,7 @@ + ((get_options & PCRE_NO_UTF8_CHECK) != 0)? " no_utf8_check" : "", + ((get_options & PCRE_DUPNAMES) != 0)? " dupnames" : ""); + +- switch (get_options & PCRE_NEWLINE_CRLF) ++ switch (get_options & PCRE_NEWLINE_BITS) + { + case PCRE_NEWLINE_CR: + fprintf(outfile, "Forced newline sequence: CR\n"); +@@ -1341,6 +1433,10 @@ + fprintf(outfile, "Forced newline sequence: CRLF\n"); + break; + ++ case PCRE_NEWLINE_ANY: ++ fprintf(outfile, "Forced newline sequence: ANY\n"); ++ break; ++ + default: + break; + } +@@ -1358,7 +1454,7 @@ + int ch = first_char & 255; + const char *caseless = ((first_char & REQ_CASELESS) == 0)? + "" : " (caseless)"; +- if (isprint(ch)) ++ if (PRINTHEX(ch)) + fprintf(outfile, "First char = \'%c\'%s\n", ch, caseless); + else + fprintf(outfile, "First char = %d%s\n", ch, caseless); +@@ -1373,7 +1469,7 @@ + int ch = need_char & 255; + const char *caseless = ((need_char & REQ_CASELESS) == 0)? + "" : " (caseless)"; +- if (isprint(ch)) ++ if (PRINTHEX(ch)) + fprintf(outfile, "Need char = \'%c\'%s\n", ch, caseless); + else + fprintf(outfile, "Need char = %d%s\n", ch, caseless); +@@ -1409,7 +1505,7 @@ + fprintf(outfile, "\n "); + c = 2; + } +- if (isprint(i) && i != ' ') ++ if (PRINTHEX(i) && i != ' ') + { + fprintf(outfile, "%c ", i); + c += 2; +@@ -1468,6 +1564,7 @@ + strerror(errno)); + } + else fprintf(outfile, "Study data written to %s\n", to_file); ++ + } + } + fclose(f); +@@ -1866,7 +1963,7 @@ + + for (;; gmatched++) /* Loop for /g or /G */ + { +- if (timeit) ++ if (timeitm > 0) + { + register int i; + clock_t time_taken; +@@ -1876,7 +1973,7 @@ + if (all_use_dfa || use_dfa) + { + int workspace[1000]; +- for (i = 0; i < LOOPREPEAT; i++) ++ for (i = 0; i < timeitm; i++) + count = pcre_dfa_exec(re, NULL, (char *)bptr, len, start_offset, + options | g_notempty, use_offsets, use_size_offsets, workspace, + sizeof(workspace)/sizeof(int)); +@@ -1884,13 +1981,13 @@ + else + #endif + +- for (i = 0; i < LOOPREPEAT; i++) ++ for (i = 0; i < timeitm; i++) + count = pcre_exec(re, extra, (char *)bptr, len, + start_offset, options | g_notempty, use_offsets, use_size_offsets); + + time_taken = clock() - start_time; +- fprintf(outfile, "Execute time %.3f milliseconds\n", +- (((double)time_taken * 1000.0) / (double)LOOPREPEAT) / ++ fprintf(outfile, "Execute time %.4f milliseconds\n", ++ (((double)time_taken * 1000.0) / (double)timeitm) / + (double)CLOCKS_PER_SEC); + } + +@@ -1966,7 +2063,28 @@ + + if (count >= 0) + { +- int i; ++ int i, maxcount; ++ ++#if !defined NODFA ++ if (all_use_dfa || use_dfa) maxcount = use_size_offsets/2; else ++#endif ++ maxcount = use_size_offsets/3; ++ ++ /* This is a check against a lunatic return value. */ ++ ++ if (count > maxcount) ++ { ++ fprintf(outfile, ++ "** PCRE error: returned count %d is too big for offset size %d\n", ++ count, use_size_offsets); ++ count = use_size_offsets/3; ++ if (do_g || do_G) ++ { ++ fprintf(outfile, "** /%c loop abandoned\n", do_g? 'g' : 'G'); ++ do_g = do_G = FALSE; /* Break g/G loop */ ++ } ++ } ++ + for (i = 0; i < count * 2; i += 2) + { + if (use_offsets[i] < 0) +@@ -2165,6 +2283,7 @@ + { + new_free((void *)tables); + setlocale(LC_CTYPE, "C"); ++ locale_set = 0; + } + } + +diff -ruN ../pcre.orig/pcrelib/ucp.h ./pcrelib/ucp.h +--- ../pcre.orig/pcrelib/ucp.h Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/ucp.h Fri Feb 9 22:31:20 2007 +@@ -6,7 +6,9 @@ + #define _UCP_H + + /* This file contains definitions of the property values that are returned by +-the function _pcre_ucp_findprop(). */ ++the function _pcre_ucp_findprop(). New values that are added for new releases ++of Unicode should always be at the end of each enum, for backwards ++compatibility. */ + + /* These are the general character categories. */ + +@@ -118,7 +120,12 @@ + ucp_Tibetan, + ucp_Tifinagh, + ucp_Ugaritic, +- ucp_Yi ++ ucp_Yi, ++ ucp_Balinese, /* New for Unicode 5.0.0 */ ++ ucp_Cuneiform, /* New for Unicode 5.0.0 */ ++ ucp_Nko, /* New for Unicode 5.0.0 */ ++ ucp_Phags_Pa, /* New for Unicode 5.0.0 */ ++ ucp_Phoenician /* New for Unicode 5.0.0 */ + }; + + #endif +diff -ruN ../pcre.orig/pcrelib/ucpinternal.h ./pcrelib/ucpinternal.h +--- ../pcre.orig/pcrelib/ucpinternal.h Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/ucpinternal.h Fri Feb 9 22:31:20 2007 +@@ -2,6 +2,9 @@ + * Unicode Property Table handler * + *************************************************/ + ++#ifndef _UCPINTERNAL_H ++#define _UCPINTERNAL_H ++ + /* Internal header file defining the layout of the bits in each pair of 32-bit + words that form a data item in the table. */ + +@@ -83,5 +86,7 @@ + (7) Otherwise, set the bottom to one element past the current point and goto + (2). + */ ++ ++#endif /* _UCPINTERNAL_H */ + + /* End of ucpinternal.h */ +diff -ruN ../pcre.orig/pcrelib/ucptable.c ./pcrelib/ucptable.c +--- ../pcre.orig/pcrelib/ucptable.c Mon Mar 6 22:45:57 2006 ++++ ./pcrelib/ucptable.c Fri Feb 9 22:31:20 2007 +@@ -1,5 +1,6 @@ + /* This source module is automatically generated from the Unicode +-property table. See ucpinternal.h for a description of the layout. */ ++property table. See ucpinternal.h for a description of the layout. ++This version was made from the Unicode 5.0.0 tables. */ + + static cnode ucp_table[] = { + { 0x09800000, 0x0000001f }, +@@ -298,7 +299,7 @@ + { 0x2100017d, 0x24000001 }, + { 0x2100017e, 0x1400ffff }, + { 0x2100017f, 0x1400fed4 }, +- { 0x21000180, 0x14000000 }, ++ { 0x21000180, 0x140000c3 }, + { 0x21000181, 0x240000d2 }, + { 0x21000182, 0x24000001 }, + { 0x21000183, 0x1400ffff }, +@@ -475,13 +476,27 @@ + { 0x21000232, 0x24000001 }, + { 0x21000233, 0x1400ffff }, + { 0x21800234, 0x14000005 }, +- { 0x2100023a, 0x24000000 }, ++ { 0x2100023a, 0x24002a2b }, + { 0x2100023b, 0x24000001 }, + { 0x2100023c, 0x1400ffff }, + { 0x2100023d, 0x2400ff5d }, +- { 0x2100023e, 0x24000000 }, ++ { 0x2100023e, 0x24002a28 }, + { 0x2180023f, 0x14000001 }, +- { 0x21000241, 0x24000053 }, ++ { 0x21000241, 0x24000001 }, ++ { 0x21000242, 0x1400ffff }, ++ { 0x21000243, 0x2400ff3d }, ++ { 0x21000244, 0x24000045 }, ++ { 0x21000245, 0x24000047 }, ++ { 0x21000246, 0x24000001 }, ++ { 0x21000247, 0x1400ffff }, ++ { 0x21000248, 0x24000001 }, ++ { 0x21000249, 0x1400ffff }, ++ { 0x2100024a, 0x24000001 }, ++ { 0x2100024b, 0x1400ffff }, ++ { 0x2100024c, 0x24000001 }, ++ { 0x2100024d, 0x1400ffff }, ++ { 0x2100024e, 0x24000001 }, ++ { 0x2100024f, 0x1400ffff }, + { 0x21800250, 0x14000002 }, + { 0x21000253, 0x1400ff2e }, + { 0x21000254, 0x1400ff32 }, +@@ -499,25 +514,30 @@ + { 0x21800264, 0x14000003 }, + { 0x21000268, 0x1400ff2f }, + { 0x21000269, 0x1400ff2d }, +- { 0x2180026a, 0x14000004 }, ++ { 0x2100026a, 0x14000000 }, ++ { 0x2100026b, 0x140029f7 }, ++ { 0x2180026c, 0x14000002 }, + { 0x2100026f, 0x1400ff2d }, + { 0x21800270, 0x14000001 }, + { 0x21000272, 0x1400ff2b }, + { 0x21800273, 0x14000001 }, + { 0x21000275, 0x1400ff2a }, +- { 0x21800276, 0x14000009 }, ++ { 0x21800276, 0x14000006 }, ++ { 0x2100027d, 0x140029e7 }, ++ { 0x2180027e, 0x14000001 }, + { 0x21000280, 0x1400ff26 }, + { 0x21800281, 0x14000001 }, + { 0x21000283, 0x1400ff26 }, + { 0x21800284, 0x14000003 }, + { 0x21000288, 0x1400ff26 }, +- { 0x21000289, 0x14000000 }, ++ { 0x21000289, 0x1400ffbb }, + { 0x2100028a, 0x1400ff27 }, + { 0x2100028b, 0x1400ff27 }, +- { 0x2180028c, 0x14000005 }, ++ { 0x2100028c, 0x1400ffb9 }, ++ { 0x2180028d, 0x14000004 }, + { 0x21000292, 0x1400ff25 }, + { 0x21000293, 0x14000000 }, +- { 0x21000294, 0x1400ffad }, ++ { 0x21000294, 0x1c000000 }, + { 0x21800295, 0x1400001a }, + { 0x218002b0, 0x18000011 }, + { 0x098002c2, 0x60000003 }, +@@ -532,6 +552,9 @@ + { 0x1b800346, 0x30000029 }, + { 0x13800374, 0x60000001 }, + { 0x1300037a, 0x18000000 }, ++ { 0x1300037b, 0x14000082 }, ++ { 0x1300037c, 0x14000082 }, ++ { 0x1300037d, 0x14000082 }, + { 0x0900037e, 0x54000000 }, + { 0x13800384, 0x60000001 }, + { 0x13000386, 0x24000026 }, +@@ -647,7 +670,9 @@ + { 0x130003fa, 0x24000001 }, + { 0x130003fb, 0x1400ffff }, + { 0x130003fc, 0x14000000 }, +- { 0x138003fd, 0x24000002 }, ++ { 0x130003fd, 0x2400ff7e }, ++ { 0x130003fe, 0x2400ff7e }, ++ { 0x130003ff, 0x2400ff7e }, + { 0x0c000400, 0x24000050 }, + { 0x0c000401, 0x24000050 }, + { 0x0c000402, 0x24000050 }, +@@ -835,7 +860,7 @@ + { 0x0c0004bd, 0x1400ffff }, + { 0x0c0004be, 0x24000001 }, + { 0x0c0004bf, 0x1400ffff }, +- { 0x0c0004c0, 0x24000000 }, ++ { 0x0c0004c0, 0x2400000f }, + { 0x0c0004c1, 0x24000001 }, + { 0x0c0004c2, 0x1400ffff }, + { 0x0c0004c3, 0x24000001 }, +@@ -850,6 +875,7 @@ + { 0x0c0004cc, 0x1400ffff }, + { 0x0c0004cd, 0x24000001 }, + { 0x0c0004ce, 0x1400ffff }, ++ { 0x0c0004cf, 0x1400fff1 }, + { 0x0c0004d0, 0x24000001 }, + { 0x0c0004d1, 0x1400ffff }, + { 0x0c0004d2, 0x24000001 }, +@@ -892,6 +918,12 @@ + { 0x0c0004f7, 0x1400ffff }, + { 0x0c0004f8, 0x24000001 }, + { 0x0c0004f9, 0x1400ffff }, ++ { 0x0c0004fa, 0x24000001 }, ++ { 0x0c0004fb, 0x1400ffff }, ++ { 0x0c0004fc, 0x24000001 }, ++ { 0x0c0004fd, 0x1400ffff }, ++ { 0x0c0004fe, 0x24000001 }, ++ { 0x0c0004ff, 0x1400ffff }, + { 0x0c000500, 0x24000001 }, + { 0x0c000501, 0x1400ffff }, + { 0x0c000502, 0x24000001 }, +@@ -908,6 +940,10 @@ + { 0x0c00050d, 0x1400ffff }, + { 0x0c00050e, 0x24000001 }, + { 0x0c00050f, 0x1400ffff }, ++ { 0x0c000510, 0x24000001 }, ++ { 0x0c000511, 0x1400ffff }, ++ { 0x0c000512, 0x24000001 }, ++ { 0x0c000513, 0x1400ffff }, + { 0x01000531, 0x24000030 }, + { 0x01000532, 0x24000030 }, + { 0x01000533, 0x24000030 }, +@@ -989,8 +1025,7 @@ + { 0x01000587, 0x14000000 }, + { 0x09000589, 0x54000000 }, + { 0x0100058a, 0x44000000 }, +- { 0x19800591, 0x30000028 }, +- { 0x198005bb, 0x30000002 }, ++ { 0x19800591, 0x3000002c }, + { 0x190005be, 0x54000000 }, + { 0x190005bf, 0x30000000 }, + { 0x190005c0, 0x54000000 }, +@@ -1043,6 +1078,13 @@ + { 0x37800780, 0x1c000025 }, + { 0x378007a6, 0x3000000a }, + { 0x370007b1, 0x1c000000 }, ++ { 0x3f8007c0, 0x34000009 }, ++ { 0x3f8007ca, 0x1c000020 }, ++ { 0x3f8007eb, 0x30000008 }, ++ { 0x3f8007f4, 0x18000001 }, ++ { 0x3f0007f6, 0x68000000 }, ++ { 0x3f8007f7, 0x54000002 }, ++ { 0x3f0007fa, 0x18000000 }, + { 0x0e800901, 0x30000001 }, + { 0x0e000903, 0x28000000 }, + { 0x0e800904, 0x1c000035 }, +@@ -1059,7 +1101,7 @@ + { 0x09800964, 0x54000001 }, + { 0x0e800966, 0x34000009 }, + { 0x09000970, 0x54000000 }, +- { 0x0e00097d, 0x1c000000 }, ++ { 0x0e80097b, 0x1c000004 }, + { 0x02000981, 0x30000000 }, + { 0x02800982, 0x28000001 }, + { 0x02800985, 0x1c000007 }, +@@ -1203,7 +1245,9 @@ + { 0x1c800cd5, 0x28000001 }, + { 0x1c000cde, 0x1c000000 }, + { 0x1c800ce0, 0x1c000001 }, ++ { 0x1c800ce2, 0x30000001 }, + { 0x1c800ce6, 0x34000009 }, ++ { 0x1c800cf1, 0x68000001 }, + { 0x24800d02, 0x28000001 }, + { 0x24800d05, 0x1c000007 }, + { 0x24800d0e, 0x1c000002 }, +@@ -1452,13 +1496,33 @@ + { 0x05801a17, 0x30000001 }, + { 0x05801a19, 0x28000002 }, + { 0x05801a1e, 0x54000001 }, ++ { 0x3d801b00, 0x30000003 }, ++ { 0x3d001b04, 0x28000000 }, ++ { 0x3d801b05, 0x1c00002e }, ++ { 0x3d001b34, 0x30000000 }, ++ { 0x3d001b35, 0x28000000 }, ++ { 0x3d801b36, 0x30000004 }, ++ { 0x3d001b3b, 0x28000000 }, ++ { 0x3d001b3c, 0x30000000 }, ++ { 0x3d801b3d, 0x28000004 }, ++ { 0x3d001b42, 0x30000000 }, ++ { 0x3d801b43, 0x28000001 }, ++ { 0x3d801b45, 0x1c000006 }, ++ { 0x3d801b50, 0x34000009 }, ++ { 0x3d801b5a, 0x54000006 }, ++ { 0x3d801b61, 0x68000009 }, ++ { 0x3d801b6b, 0x30000008 }, ++ { 0x3d801b74, 0x68000008 }, + { 0x21801d00, 0x1400002b }, + { 0x21801d2c, 0x18000035 }, + { 0x21801d62, 0x14000015 }, + { 0x0c001d78, 0x18000000 }, +- { 0x21801d79, 0x14000021 }, ++ { 0x21801d79, 0x14000003 }, ++ { 0x21001d7d, 0x14000ee6 }, ++ { 0x21801d7e, 0x1400001c }, + { 0x21801d9b, 0x18000024 }, +- { 0x1b801dc0, 0x30000003 }, ++ { 0x1b801dc0, 0x3000000a }, ++ { 0x1b801dfe, 0x30000001 }, + { 0x21001e00, 0x24000001 }, + { 0x21001e01, 0x1400ffff }, + { 0x21001e02, 0x24000001 }, +@@ -1967,7 +2031,7 @@ + { 0x1b8020dd, 0x2c000003 }, + { 0x1b0020e1, 0x30000000 }, + { 0x1b8020e2, 0x2c000002 }, +- { 0x1b8020e5, 0x30000006 }, ++ { 0x1b8020e5, 0x3000000a }, + { 0x09802100, 0x68000001 }, + { 0x09002102, 0x24000000 }, + { 0x09802103, 0x68000003 }, +@@ -1995,7 +2059,7 @@ + { 0x0900212e, 0x68000000 }, + { 0x0900212f, 0x14000000 }, + { 0x09802130, 0x24000001 }, +- { 0x09002132, 0x68000000 }, ++ { 0x21002132, 0x2400001c }, + { 0x09002133, 0x24000000 }, + { 0x09002134, 0x14000000 }, + { 0x09802135, 0x1c000003 }, +@@ -2008,7 +2072,8 @@ + { 0x09802146, 0x14000003 }, + { 0x0900214a, 0x68000000 }, + { 0x0900214b, 0x64000000 }, +- { 0x0900214c, 0x68000000 }, ++ { 0x0980214c, 0x68000001 }, ++ { 0x2100214e, 0x1400ffe4 }, + { 0x09802153, 0x3c00000c }, + { 0x09002160, 0x38000010 }, + { 0x09002161, 0x38000010 }, +@@ -2042,7 +2107,9 @@ + { 0x0900217d, 0x3800fff0 }, + { 0x0900217e, 0x3800fff0 }, + { 0x0900217f, 0x3800fff0 }, +- { 0x09802180, 0x38000003 }, ++ { 0x09802180, 0x38000002 }, ++ { 0x09002183, 0x24000001 }, ++ { 0x21002184, 0x1400ffff }, + { 0x09802190, 0x64000004 }, + { 0x09802195, 0x68000004 }, + { 0x0980219a, 0x64000001 }, +@@ -2073,10 +2140,9 @@ + { 0x0900237c, 0x64000000 }, + { 0x0980237d, 0x6800001d }, + { 0x0980239b, 0x64000018 }, +- { 0x090023b4, 0x58000000 }, +- { 0x090023b5, 0x48000000 }, +- { 0x090023b6, 0x54000000 }, +- { 0x098023b7, 0x68000024 }, ++ { 0x098023b4, 0x68000027 }, ++ { 0x098023dc, 0x64000005 }, ++ { 0x098023e2, 0x68000005 }, + { 0x09802400, 0x68000026 }, + { 0x09802440, 0x6800000a }, + { 0x09802460, 0x3c00003b }, +@@ -2143,7 +2209,7 @@ + { 0x09802600, 0x6800006e }, + { 0x0900266f, 0x64000000 }, + { 0x09802670, 0x6800002c }, +- { 0x098026a0, 0x68000011 }, ++ { 0x098026a0, 0x68000012 }, + { 0x09802701, 0x68000003 }, + { 0x09802706, 0x68000003 }, + { 0x0980270c, 0x6800001b }, +@@ -2174,6 +2240,7 @@ + { 0x098027c0, 0x64000004 }, + { 0x090027c5, 0x58000000 }, + { 0x090027c6, 0x48000000 }, ++ { 0x098027c7, 0x64000003 }, + { 0x098027d0, 0x64000015 }, + { 0x090027e6, 0x58000000 }, + { 0x090027e7, 0x48000000 }, +@@ -2215,7 +2282,8 @@ + { 0x090029fc, 0x58000000 }, + { 0x090029fd, 0x48000000 }, + { 0x098029fe, 0x64000101 }, +- { 0x09802b00, 0x68000013 }, ++ { 0x09802b00, 0x6800001a }, ++ { 0x09802b20, 0x68000003 }, + { 0x11002c00, 0x24000030 }, + { 0x11002c01, 0x24000030 }, + { 0x11002c02, 0x24000030 }, +@@ -2310,6 +2378,23 @@ + { 0x11002c5c, 0x1400ffd0 }, + { 0x11002c5d, 0x1400ffd0 }, + { 0x11002c5e, 0x1400ffd0 }, ++ { 0x21002c60, 0x24000001 }, ++ { 0x21002c61, 0x1400ffff }, ++ { 0x21002c62, 0x2400d609 }, ++ { 0x21002c63, 0x2400f11a }, ++ { 0x21002c64, 0x2400d619 }, ++ { 0x21002c65, 0x1400d5d5 }, ++ { 0x21002c66, 0x1400d5d8 }, ++ { 0x21002c67, 0x24000001 }, ++ { 0x21002c68, 0x1400ffff }, ++ { 0x21002c69, 0x24000001 }, ++ { 0x21002c6a, 0x1400ffff }, ++ { 0x21002c6b, 0x24000001 }, ++ { 0x21002c6c, 0x1400ffff }, ++ { 0x21002c74, 0x14000000 }, ++ { 0x21002c75, 0x24000001 }, ++ { 0x21002c76, 0x1400ffff }, ++ { 0x21002c77, 0x14000000 }, + { 0x0a002c80, 0x24000001 }, + { 0x0a002c81, 0x1400ffff }, + { 0x0a002c82, 0x24000001 }, +@@ -2559,6 +2644,8 @@ + { 0x3c80a016, 0x1c000476 }, + { 0x3c80a490, 0x68000036 }, + { 0x0980a700, 0x60000016 }, ++ { 0x0980a717, 0x18000003 }, ++ { 0x0980a720, 0x60000001 }, + { 0x3080a800, 0x1c000001 }, + { 0x3000a802, 0x28000000 }, + { 0x3080a803, 0x1c000002 }, +@@ -2570,6 +2657,8 @@ + { 0x3080a825, 0x30000001 }, + { 0x3000a827, 0x28000000 }, + { 0x3080a828, 0x68000003 }, ++ { 0x4080a840, 0x1c000033 }, ++ { 0x4080a874, 0x54000003 }, + { 0x1780ac00, 0x1c002ba3 }, + { 0x0980d800, 0x1000037f }, + { 0x0980db80, 0x1000007f }, +@@ -2765,13 +2854,15 @@ + { 0x1301018a, 0x3c000000 }, + { 0x29810300, 0x1c00001e }, + { 0x29810320, 0x3c000003 }, +- { 0x12810330, 0x1c000019 }, ++ { 0x12810330, 0x1c000010 }, ++ { 0x12010341, 0x38000000 }, ++ { 0x12810342, 0x1c000007 }, + { 0x1201034a, 0x38000000 }, + { 0x3b810380, 0x1c00001d }, + { 0x3b01039f, 0x54000000 }, + { 0x2a8103a0, 0x1c000023 }, + { 0x2a8103c8, 0x1c000007 }, +- { 0x2a0103d0, 0x68000000 }, ++ { 0x2a0103d0, 0x54000000 }, + { 0x2a8103d1, 0x38000004 }, + { 0x0d010400, 0x24000028 }, + { 0x0d010401, 0x24000028 }, +@@ -2861,6 +2952,9 @@ + { 0x0b810837, 0x1c000001 }, + { 0x0b01083c, 0x1c000000 }, + { 0x0b01083f, 0x1c000000 }, ++ { 0x41810900, 0x1c000015 }, ++ { 0x41810916, 0x3c000003 }, ++ { 0x4101091f, 0x54000000 }, + { 0x1e010a00, 0x1c000000 }, + { 0x1e810a01, 0x30000002 }, + { 0x1e810a05, 0x30000001 }, +@@ -2872,6 +2966,9 @@ + { 0x1e010a3f, 0x30000000 }, + { 0x1e810a40, 0x3c000007 }, + { 0x1e810a50, 0x54000008 }, ++ { 0x3e812000, 0x1c00036e }, ++ { 0x3e812400, 0x38000062 }, ++ { 0x3e812470, 0x54000003 }, + { 0x0981d000, 0x680000f5 }, + { 0x0981d100, 0x68000026 }, + { 0x0981d12a, 0x6800003a }, +@@ -2890,6 +2987,7 @@ + { 0x1381d242, 0x30000002 }, + { 0x1301d245, 0x68000000 }, + { 0x0981d300, 0x68000056 }, ++ { 0x0981d360, 0x3c000011 }, + { 0x0981d400, 0x24000019 }, + { 0x0981d41a, 0x14000019 }, + { 0x0981d434, 0x24000019 }, +@@ -2957,6 +3055,8 @@ + { 0x0981d7aa, 0x14000018 }, + { 0x0901d7c3, 0x64000000 }, + { 0x0981d7c4, 0x14000005 }, ++ { 0x0901d7ca, 0x24000000 }, ++ { 0x0901d7cb, 0x14000000 }, + { 0x0981d7ce, 0x34000031 }, + { 0x16820000, 0x1c00a6d6 }, + { 0x1682f800, 0x1c00021d }, |