From 47db112512e23853b60b6ecea208056818e10907 Mon Sep 17 00:00:00 2001 From: Nigel Metheringham Date: Mon, 12 Nov 2007 13:02:19 +0000 Subject: [PATCH] Updated embedded PCRE to version 7.4 to avoid 2 CVE issues:- CVE-2007-1659 CVE-2007-1660 Fixes: bug # 628 --- doc/doc-txt/ChangeLog | 8 +- src/OS/Makefile-Base | 4 +- src/src/pcre/ChangeLog | 242 +++++++++++- src/src/pcre/config.h | 7 +- src/src/pcre/dftables.c | 11 +- src/src/pcre/pcre.h | 37 +- src/src/pcre/pcre_chartables.c | 8 +- src/src/pcre/pcre_compile.c | 667 ++++++++++++++++++++++++-------- src/src/pcre/pcre_config.c | 14 +- src/src/pcre/pcre_exec.c | 363 +++++++++++------ src/src/pcre/pcre_fullinfo.c | 20 +- src/src/pcre/pcre_get.c | 8 +- src/src/pcre/pcre_globals.c | 6 +- src/src/pcre/pcre_internal.h | 96 +++-- src/src/pcre/pcre_maketables.c | 7 +- src/src/pcre/pcre_newline.c | 10 +- src/src/pcre/pcre_printint.src | 6 +- src/src/pcre/pcre_study.c | 9 +- src/src/pcre/pcre_tables.c | 333 ++++++++++------ src/src/pcre/pcre_try_flipped.c | 7 +- src/src/pcre/pcre_version.c | 6 +- src/src/pcre/pcretest.c | 101 +++-- 22 files changed, 1474 insertions(+), 496 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 83879f0e8..3d9be185f 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,8 +1,11 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.535 2007/10/18 12:08:47 nm4 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.536 2007/11/12 13:02:19 nm4 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- +Exim version 4.69 +----------------- + TK/01 Add preliminary DKIM support. Currently requires a forked version of ALT-N's libdkim that I have put here: http://duncanthrax.net/exim-experimental/ @@ -23,6 +26,9 @@ NM/02 Bugzilla 619: Defended against bad data coming back from gethostbyaddr NM/03 Bugzilla 613: Documentation fix for acl_not_smtp +NM/04 Bugzilla 628: PCRE update to 7.4 (work done by John Hall) + + Exim version 4.68 ----------------- diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index ac5a4d822..6740e733c 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/OS/Makefile-Base,v 1.11 2007/09/28 12:21:57 tom Exp $ +# $Cambridge: exim/src/OS/Makefile-Base,v 1.12 2007/11/12 13:02:19 nm4 Exp $ # This file is the basis of the main makefile for Exim and friends. The # makefile at the top level arranges to build the main makefile by calling @@ -655,7 +655,7 @@ $(MONBIN): $(HDRS) buildpcre: @(cd pcre; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" \ - FE="$(FE)" CFLAGS="$(CFLAGS) $(PCRE_CFLAGS)" \ + FE="$(FE)" CFLAGS="$(CFLAGS) $(PCRE_CFLAGS) -DHAVE_CONFIG_H" \ RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)") @if $(SHELL) $(SCRIPTS)/newer pcre/libpcre.a exim; then \ diff --git a/src/src/pcre/ChangeLog b/src/src/pcre/ChangeLog index 87c2de74d..cff73670a 100644 --- a/src/src/pcre/ChangeLog +++ b/src/src/pcre/ChangeLog @@ -1,7 +1,247 @@ ChangeLog for PCRE ------------------ -Version 7.2 19-June-07 +Version 7.4 21-Sep-07 +--------------------- + +1. Change 7.3/28 was implemented for classes by looking at the bitmap. This + means that a class such as [\s] counted as "explicit reference to CR or + LF". That isn't really right - the whole point of the change was to try to + help when there was an actual mention of one of the two characters. So now + the change happens only if \r or \n (or a literal CR or LF) character is + encountered. + +2. The 32-bit options word was also used for 6 internal flags, but the numbers + of both had grown to the point where there were only 3 bits left. + Fortunately, there was spare space in the data structure, and so I have + moved the internal flags into a new 16-bit field to free up more option + bits. + +3. The appearance of (?J) at the start of a pattern set the DUPNAMES option, + but did not set the internal JCHANGED flag - either of these is enough to + control the way the "get" function works - but the PCRE_INFO_JCHANGED + facility is supposed to tell if (?J) was ever used, so now (?J) at the + start sets both bits. + +4. Added options (at build time, compile time, exec time) to change \R from + matching any Unicode line ending sequence to just matching CR, LF, or CRLF. + +5. doc/pcresyntax.html was missing from the distribution. + +6. Put back the definition of PCRE_ERROR_NULLWSLIMIT, for backward + compatibility, even though it is no longer used. + +7. Added macro for snprintf to pcrecpp_unittest.cc and also for strtoll and + strtoull to pcrecpp.cc to select the available functions in WIN32 when the + windows.h file is present (where different names are used). [This was + reversed later after testing - see 16 below.] + +8. Changed all #include to #include "config.h". There were also + some further cases that I changed to "pcre.h". + +9. When pcregrep was used with the --colour option, it missed the line ending + sequence off the lines that it output. + +10. It was pointed out to me that arrays of string pointers cause lots of + relocations when a shared library is dynamically loaded. A technique of + using a single long string with a table of offsets can drastically reduce + these. I have refactored PCRE in four places to do this. The result is + dramatic: + + Originally: 290 + After changing UCP table: 187 + After changing error message table: 43 + After changing table of "verbs" 36 + After changing table of Posix names 22 + + Thanks to the folks working on Gregex for glib for this insight. + +11. --disable-stack-for-recursion caused compiling to fail unless -enable- + unicode-properties was also set. + +12. Updated the tests so that they work when \R is defaulted to ANYCRLF. + +13. Added checks for ANY and ANYCRLF to pcrecpp.cc where it previously + checked only for CRLF. + +14. Added casts to pcretest.c to avoid compiler warnings. + +15. Added Craig's patch to various pcrecpp modules to avoid compiler warnings. + +16. Added Craig's patch to remove the WINDOWS_H tests, that were not working, + and instead check for _strtoi64 explicitly, and avoid the use of snprintf() + entirely. This removes changes made in 7 above. + +17. The CMake files have been updated, and there is now more information about + building with CMake in the NON-UNIX-USE document. + + +Version 7.3 28-Aug-07 +--------------------- + + 1. In the rejigging of the build system that eventually resulted in 7.1, the + line "#include " was included in pcre_internal.h. The use of angle + brackets there is not right, since it causes compilers to look for an + installed pcre.h, not the version that is in the source that is being + compiled (which of course may be different). I have changed it back to: + + #include "pcre.h" + + I have a vague recollection that the change was concerned with compiling in + different directories, but in the new build system, that is taken care of + by the VPATH setting the Makefile. + + 2. The pattern .*$ when run in not-DOTALL UTF-8 mode with newline=any failed + when the subject happened to end in the byte 0x85 (e.g. if the last + character was \x{1ec5}). *Character* 0x85 is one of the "any" newline + characters but of course it shouldn't be taken as a newline when it is part + of another character. The bug was that, for an unlimited repeat of . in + not-DOTALL UTF-8 mode, PCRE was advancing by bytes rather than by + characters when looking for a newline. + + 3. A small performance improvement in the DOTALL UTF-8 mode .* case. + + 4. Debugging: adjusted the names of opcodes for different kinds of parentheses + in debug output. + + 5. Arrange to use "%I64d" instead of "%lld" and "%I64u" instead of "%llu" for + long printing in the pcrecpp unittest when running under MinGW. + + 6. ESC_K was left out of the EBCDIC table. + + 7. Change 7.0/38 introduced a new limit on the number of nested non-capturing + parentheses; I made it 1000, which seemed large enough. Unfortunately, the + limit also applies to "virtual nesting" when a pattern is recursive, and in + this case 1000 isn't so big. I have been able to remove this limit at the + expense of backing off one optimization in certain circumstances. Normally, + when pcre_exec() would call its internal match() function recursively and + immediately return the result unconditionally, it uses a "tail recursion" + feature to save stack. However, when a subpattern that can match an empty + string has an unlimited repetition quantifier, it no longer makes this + optimization. That gives it a stack frame in which to save the data for + checking that an empty string has been matched. Previously this was taken + from the 1000-entry workspace that had been reserved. So now there is no + explicit limit, but more stack is used. + + 8. Applied Daniel's patches to solve problems with the import/export magic + syntax that is required for Windows, and which was going wrong for the + pcreposix and pcrecpp parts of the library. These were overlooked when this + problem was solved for the main library. + + 9. There were some crude static tests to avoid integer overflow when computing + the size of patterns that contain repeated groups with explicit upper + limits. As the maximum quantifier is 65535, the maximum group length was + set at 30,000 so that the product of these two numbers did not overflow a + 32-bit integer. However, it turns out that people want to use groups that + are longer than 30,000 bytes (though not repeat them that many times). + Change 7.0/17 (the refactoring of the way the pattern size is computed) has + made it possible to implement the integer overflow checks in a much more + dynamic way, which I have now done. The artificial limitation on group + length has been removed - we now have only the limit on the total length of + the compiled pattern, which depends on the LINK_SIZE setting. + +10. Fixed a bug in the documentation for get/copy named substring when + duplicate names are permitted. If none of the named substrings are set, the + functions return PCRE_ERROR_NOSUBSTRING (7); the doc said they returned an + empty string. + +11. Because Perl interprets \Q...\E at a high level, and ignores orphan \E + instances, patterns such as [\Q\E] or [\E] or even [^\E] cause an error, + because the ] is interpreted as the first data character and the + terminating ] is not found. PCRE has been made compatible with Perl in this + regard. Previously, it interpreted [\Q\E] as an empty class, and [\E] could + cause memory overwriting. + +10. Like Perl, PCRE automatically breaks an unlimited repeat after an empty + string has been matched (to stop an infinite loop). It was not recognizing + a conditional subpattern that could match an empty string if that + subpattern was within another subpattern. For example, it looped when + trying to match (((?(1)X|))*) but it was OK with ((?(1)X|)*) where the + condition was not nested. This bug has been fixed. + +12. A pattern like \X?\d or \P{L}?\d in non-UTF-8 mode could cause a backtrack + past the start of the subject in the presence of bytes with the top bit + set, for example "\x8aBCD". + +13. Added Perl 5.10 experimental backtracking controls (*FAIL), (*F), (*PRUNE), + (*SKIP), (*THEN), (*COMMIT), and (*ACCEPT). + +14. Optimized (?!) to (*FAIL). + +15. Updated the test for a valid UTF-8 string to conform to the later RFC 3629. + This restricts code points to be within the range 0 to 0x10FFFF, excluding + the "low surrogate" sequence 0xD800 to 0xDFFF. Previously, PCRE allowed the + full range 0 to 0x7FFFFFFF, as defined by RFC 2279. Internally, it still + does: it's just the validity check that is more restrictive. + +16. Inserted checks for integer overflows during escape sequence (backslash) + processing, and also fixed erroneous offset values for syntax errors during + backslash processing. + +17. Fixed another case of looking too far back in non-UTF-8 mode (cf 12 above) + for patterns like [\PPP\x8a]{1,}\x80 with the subject "A\x80". + +18. An unterminated class in a pattern like (?1)\c[ with a "forward reference" + caused an overrun. + +19. A pattern like (?:[\PPa*]*){8,} which had an "extended class" (one with + something other than just ASCII characters) inside a group that had an + unlimited repeat caused a loop at compile time (while checking to see + whether the group could match an empty string). + +20. Debugging a pattern containing \p or \P could cause a crash. For example, + [\P{Any}] did so. (Error in the code for printing property names.) + +21. An orphan \E inside a character class could cause a crash. + +22. A repeated capturing bracket such as (A)? could cause a wild memory + reference during compilation. + +23. There are several functions in pcre_compile() that scan along a compiled + expression for various reasons (e.g. to see if it's fixed length for look + behind). There were bugs in these functions when a repeated \p or \P was + present in the pattern. These operators have additional parameters compared + with \d, etc, and these were not being taken into account when moving along + the compiled data. Specifically: + + (a) A item such as \p{Yi}{3} in a lookbehind was not treated as fixed + length. + + (b) An item such as \pL+ within a repeated group could cause crashes or + loops. + + (c) A pattern such as \p{Yi}+(\P{Yi}+)(?1) could give an incorrect + "reference to non-existent subpattern" error. + + (d) A pattern like (\P{Yi}{2}\277)? could loop at compile time. + +24. A repeated \S or \W in UTF-8 mode could give wrong answers when multibyte + characters were involved (for example /\S{2}/8g with "A\x{a3}BC"). + +25. Using pcregrep in multiline, inverted mode (-Mv) caused it to loop. + +26. Patterns such as [\P{Yi}A] which include \p or \P and just one other + character were causing crashes (broken optimization). + +27. Patterns such as (\P{Yi}*\277)* (group with possible zero repeat containing + \p or \P) caused a compile-time loop. + +28. More problems have arisen in unanchored patterns when CRLF is a valid line + break. For example, the unstudied pattern [\r\n]A does not match the string + "\r\nA" because change 7.0/46 below moves the current point on by two + characters after failing to match at the start. However, the pattern \nA + *does* match, because it doesn't start till \n, and if [\r\n]A is studied, + the same is true. There doesn't seem any very clean way out of this, but + what I have chosen to do makes the common cases work: PCRE now takes note + of whether there can be an explicit match for \r or \n anywhere in the + pattern, and if so, 7.0/46 no longer applies. As part of this change, + there's a new PCRE_INFO_HASCRORLF option for finding out whether a compiled + pattern has explicit CR or LF references. + +29. Added (*CR) etc for changing newline setting at start of pattern. + + +Version 7.2 19-Jun-07 --------------------- 1. If the fr_FR locale cannot be found for test 3, try the "french" locale, diff --git a/src/src/pcre/config.h b/src/src/pcre/config.h index 51bd998bb..1cd8fcfe3 100644 --- a/src/src/pcre/config.h +++ b/src/src/pcre/config.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/config.h,v 1.3 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/config.h,v 1.4 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * config.h for PCRE for Exim * @@ -19,6 +19,9 @@ in its os.h-SunOS4 file. We interface this to PCRE by including the os.h file here, and then defining HAVE_MEMOVE so that PCRE's code in internal.h leaves things alone. */ +#ifndef PCRE_CONFIG_H +#define PCRE_CONFIG_H + #include "../os.h" #define HAVE_MEMMOVE 1 @@ -40,4 +43,6 @@ and non-ASCII systems. For Exim's purposes, just flatten it. */ #undef EBCDIC +#endif // include once + /* End */ diff --git a/src/src/pcre/dftables.c b/src/src/pcre/dftables.c index e1a2d6f83..33183496f 100644 --- a/src/src/pcre/dftables.c +++ b/src/src/pcre/dftables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/dftables.c,v 1.6 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/dftables.c,v 1.7 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -45,6 +45,10 @@ character tables for PCRE. The tables are built according to the current locale. Now that pcre_maketables is a function visible to the outside world, we make use of its code from here in order to be consistent. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -101,12 +105,15 @@ fprintf(f, "tables are passed to PCRE by the application that calls it. The tables\n" "are used only for characters whose code values are less than 256.\n\n"); fprintf(f, - "The following #include is present because without it gcc 4.x may remove\n" + "The following #includes are present because without them 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" + "#ifdef HAVE_CONFIG_H\n" + "#include \"config.h\"\n" + "#endif\n\n" "#include \"pcre_internal.h\"\n\n"); fprintf(f, "const unsigned char _pcre_default_tables[] = {\n\n" diff --git a/src/src/pcre/pcre.h b/src/src/pcre/pcre.h index c46b8acd7..5e37c9270 100644 --- a/src/src/pcre/pcre.h +++ b/src/src/pcre/pcre.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre.h,v 1.6 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre.h,v 1.7 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -51,12 +51,18 @@ POSSIBILITY OF SUCH DAMAGE. /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE, the appropriate export setting is defined in pcre_internal.h, which includes this file. So we -don't change an existing definition of PCRE_EXP_DECL. */ +don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ -#ifndef PCRE_EXP_DECL -# ifdef _WIN32 -# ifndef PCRE_STATIC -# define PCRE_EXP_DECL extern __declspec(dllimport) +#if defined(_WIN32) && !defined(PCRE_STATIC) +# ifndef PCRE_EXP_DECL +# define PCRE_EXP_DECL extern __declspec(dllimport) +# endif +# ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern __declspec(dllimport) +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN __declspec(dllimport) # endif # endif #endif @@ -65,9 +71,18 @@ don't change an existing definition of PCRE_EXP_DECL. */ #ifndef PCRE_EXP_DECL # ifdef __cplusplus -# define PCRE_EXP_DECL extern "C" +# define PCRE_EXP_DECL extern "C" # else -# define PCRE_EXP_DECL extern +# define PCRE_EXP_DECL extern +# endif +#endif + +#ifdef __cplusplus +# ifndef PCRECPP_EXP_DECL +# define PCRECPP_EXP_DECL extern +# endif +# ifndef PCRECPP_EXP_DEFN +# define PCRECPP_EXP_DEFN # endif #endif @@ -109,6 +124,8 @@ extern "C" { #define PCRE_NEWLINE_CRLF 0x00300000 #define PCRE_NEWLINE_ANY 0x00400000 #define PCRE_NEWLINE_ANYCRLF 0x00500000 +#define PCRE_BSR_ANYCRLF 0x00800000 +#define PCRE_BSR_UNICODE 0x01000000 /* Exec-time and get/set-time error codes */ @@ -134,7 +151,7 @@ extern "C" { #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_NULLWSLIMIT (-22) /* No longer actually used */ #define PCRE_ERROR_BADNEWLINE (-23) /* Request types for pcre_fullinfo() */ @@ -154,6 +171,7 @@ extern "C" { #define PCRE_INFO_DEFAULT_TABLES 11 #define PCRE_INFO_OKPARTIAL 12 #define PCRE_INFO_JCHANGED 13 +#define PCRE_INFO_HASCRORLF 14 /* Request types for pcre_config(). Do not re-arrange, in order to remain compatible. */ @@ -166,6 +184,7 @@ compatible. */ #define PCRE_CONFIG_STACKRECURSE 5 #define PCRE_CONFIG_UNICODE_PROPERTIES 6 #define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 +#define PCRE_CONFIG_BSR 8 /* Bit flags for the pcre_extra structure. Do not re-arrange or redefine these bits, just add new ones on the end, in order to remain compatible. */ diff --git a/src/src/pcre/pcre_chartables.c b/src/src/pcre/pcre_chartables.c index acc852821..84ae8c91b 100644 --- a/src/src/pcre/pcre_chartables.c +++ b/src/src/pcre/pcre_chartables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_chartables.c,v 1.1 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_chartables.c,v 1.2 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -16,12 +16,16 @@ example ISO-8859-1. When dftables is run, it creates these tables in the current locale. If PCRE is configured with --enable-rebuild-chartables, this happens automatically. -The following #include is present because without it gcc 4.x may remove the +The following #includes are present because without the gcc 4.x may remove the array definition from the final binary if PCRE is built into a static library and dead code stripping is activated. This leads to link errors. Pulling in the header ensures that the array gets flagged as "someone outside this compilation unit might reference this" and so it will always be supplied to the linker. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" const unsigned char _pcre_default_tables[] = { diff --git a/src/src/pcre/pcre_compile.c b/src/src/pcre/pcre_compile.c index 4d179e3fe..98c307947 100644 --- a/src/src/pcre/pcre_compile.c +++ b/src/src/pcre/pcre_compile.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_compile.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_compile.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -44,11 +44,14 @@ POSSIBILITY OF SUCH DAMAGE. supporting internal functions that are not used by other modules. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #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" @@ -64,6 +67,13 @@ used by pcretest. DEBUG is not defined when building a production library. */ #define SETBIT(a,b) a[b/8] |= (1 << (b%8)) +/* Maximum length value to check against when making sure that the integer that +holds the compiled pattern length does not overflow. We make it a bit less than +INT_MAX to allow for adding in group terminating bytes, so that we don't have +to check them every time. */ + +#define OFLOW_MAX (INT_MAX - 20) + /************************************************* * Code parameters and static tables * @@ -122,7 +132,7 @@ static const short int escapes[] = { /* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', /* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, /* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, -/* D0 */ '}', 0, 0, 0, 0, 0, 0, -ESC_P, +/* D0 */ '}', 0, -ESC_K, 0, 0, 0, 0, -ESC_P, /* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, /* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, /* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, @@ -132,14 +142,47 @@ static const short int escapes[] = { #endif -/* Tables of names of POSIX character classes and their lengths. The list is -terminated by a zero length entry. The first three must be alpha, lower, upper, -as this is assumed for handling case independence. */ +/* Table of special "verbs" like (*PRUNE). This is a short table, so it is +searched linearly. Put all the names into a single string, in order to reduce +the number of relocations when a shared library is dynamically linked. */ + +typedef struct verbitem { + int len; + int op; +} verbitem; + +static const char verbnames[] = + "ACCEPT\0" + "COMMIT\0" + "F\0" + "FAIL\0" + "PRUNE\0" + "SKIP\0" + "THEN"; + +static verbitem verbs[] = { + { 6, OP_ACCEPT }, + { 6, OP_COMMIT }, + { 1, OP_FAIL }, + { 4, OP_FAIL }, + { 5, OP_PRUNE }, + { 4, OP_SKIP }, + { 4, OP_THEN } +}; + +static int verbcount = sizeof(verbs)/sizeof(verbitem); + -static const char *const posix_names[] = { - "alpha", "lower", "upper", - "alnum", "ascii", "blank", "cntrl", "digit", "graph", - "print", "punct", "space", "word", "xdigit" }; +/* Tables of names of POSIX character classes and their lengths. The names are +now all in a single string, to reduce the number of relocations when a shared +library is dynamically loaded. The list of lengths is terminated by a zero +length entry. The first three must be alpha, lower, upper, as this is assumed +for handling case independence. */ + +static const char posix_names[] = + "alpha\0" "lower\0" "upper\0" "alnum\0" "ascii\0" "blank\0" + "cntrl\0" "digit\0" "graph\0" "print\0" "punct\0" "space\0" + "word\0" "xdigit"; static const uschar posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; @@ -178,80 +221,88 @@ static const int posix_class_maps[] = { /* The texts of compile-time error messages. These are "char *" because they 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", - "\\ at end of pattern", - "\\c at end of pattern", - "unrecognized character follows \\", - "numbers out of order in {} quantifier", +are no longer used. This used to be a table of strings, but in order to reduce +the number of relocations needed when a shared library is loaded dynamically, +it is now one long string. We cannot use a table of offsets, because the +lengths of inserts such as XSTRING(MAX_NAME_SIZE) are not known. Instead, we +simply count through to the one we want - this isn't a performance issue +because these strings are used only when there is a compilation error. */ + +static const char error_texts[] = + "no error\0" + "\\ at end of pattern\0" + "\\c at end of pattern\0" + "unrecognized character follows \\\0" + "numbers out of order in {} quantifier\0" /* 5 */ - "number too big in {} quantifier", - "missing terminating ] for character class", - "invalid escape sequence in character class", - "range out of order in character class", - "nothing to repeat", + "number too big in {} quantifier\0" + "missing terminating ] for character class\0" + "invalid escape sequence in character class\0" + "range out of order in character class\0" + "nothing to repeat\0" /* 10 */ - "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", - "missing )", + "operand of unlimited repeat could match the empty string\0" /** DEAD **/ + "internal error: unexpected repeat\0" + "unrecognized character after (?\0" + "POSIX named classes are supported only within a class\0" + "missing )\0" /* 15 */ - "reference to non-existent subpattern", - "erroffset passed as NULL", - "unknown option bit(s) set", - "missing ) after comment", - "parentheses nested too deeply", /** DEAD **/ + "reference to non-existent subpattern\0" + "erroffset passed as NULL\0" + "unknown option bit(s) set\0" + "missing ) after comment\0" + "parentheses nested too deeply\0" /** DEAD **/ /* 20 */ - "regular expression too large", - "failed to get memory", - "unmatched parentheses", - "internal error: code overflow", - "unrecognized character after (?<", + "regular expression is too large\0" + "failed to get memory\0" + "unmatched parentheses\0" + "internal error: code overflow\0" + "unrecognized character after (?<\0" /* 25 */ - "lookbehind assertion is not fixed length", - "malformed number or name after (?(", - "conditional group contains more than two branches", - "assertion expected after (?(", - "(?R or (?[+-]digits must be followed by )", + "lookbehind assertion is not fixed length\0" + "malformed number or name after (?(\0" + "conditional group contains more than two branches\0" + "assertion expected after (?(\0" + "(?R or (?[+-]digits must be followed by )\0" /* 30 */ - "unknown POSIX class name", - "POSIX collating elements are not supported", - "this version of PCRE is not compiled with PCRE_UTF8 support", - "spare error", /** DEAD **/ - "character value in \\x{...} sequence is too large", + "unknown POSIX class name\0" + "POSIX collating elements are not supported\0" + "this version of PCRE is not compiled with PCRE_UTF8 support\0" + "spare error\0" /** DEAD **/ + "character value in \\x{...} sequence is too large\0" /* 35 */ - "invalid condition (?(0)", - "\\C not allowed in lookbehind assertion", - "PCRE does not support \\L, \\l, \\N, \\U, or \\u", - "number after (?C is > 255", - "closing ) for (?C expected", + "invalid condition (?(0)\0" + "\\C not allowed in lookbehind assertion\0" + "PCRE does not support \\L, \\l, \\N, \\U, or \\u\0" + "number after (?C is > 255\0" + "closing ) for (?C expected\0" /* 40 */ - "recursive call could loop indefinitely", - "unrecognized character after (?P", - "syntax error in subpattern name (missing terminator)", - "two named subpatterns have the same name", - "invalid UTF-8 string", + "recursive call could loop indefinitely\0" + "unrecognized character after (?P\0" + "syntax error in subpattern name (missing terminator)\0" + "two named subpatterns have the same name\0" + "invalid UTF-8 string\0" /* 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 " XSTRING(MAX_NAME_SIZE) " characters)", - "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")", + "support for \\P, \\p, and \\X has not been compiled\0" + "malformed \\P or \\p sequence\0" + "unknown property name after \\P or \\p\0" + "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0" + "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" /* 50 */ - "repeated subpattern is too long", - "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", + "repeated subpattern is too long\0" /** DEAD **/ + "octal value is greater than \\377 (not in UTF-8 mode)\0" + "internal error: overran compiling workspace\0" + "internal error: previously-checked referenced subpattern not found\0" + "DEFINE group contains more than one branch\0" /* 55 */ - "repeating a DEFINE group is not allowed", - "inconsistent NEWLINE options", - "\\g is not followed by a braced name or an optionally braced non-zero number", - "(?+ or (?- or (?(+ or (?(- must be followed by a non-zero number" -}; + "repeating a DEFINE group is not allowed\0" + "inconsistent NEWLINE options\0" + "\\g is not followed by a braced name or an optionally braced non-zero number\0" + "(?+ or (?- or (?(+ or (?(- must be followed by a non-zero number\0" + "(*VERB) with an argument is not supported\0" + /* 60 */ + "(*VERB) not recognized\0" + "number is too big"; /* Table to identify digits and hex digits. This is used when compiling @@ -386,6 +437,28 @@ static BOOL +/************************************************* +* Find an error text * +*************************************************/ + +/* The error texts are now all in one long string, to save on relocations. As +some of the text is of unknown length, we can't use a table of offsets. +Instead, just count through the strings. This is not a performance issue +because it happens only when there has been a compilation error. + +Argument: the error number +Returns: pointer to the error string +*/ + +static const char * +find_error_text(int n) +{ +const char *s = error_texts; +for (; n > 0; n--) while (*s++ != 0); +return s; +} + + /************************************************* * Handle escapes * *************************************************/ @@ -407,7 +480,7 @@ Arguments: Returns: zero or positive => a data character negative => a special escape sequence - on error, errorptr is set + on error, errorcodeptr is set */ static int @@ -492,10 +565,16 @@ else while ((digitab[ptr[1]] & ctype_digit) != 0) c = c * 10 + *(++ptr) - '0'; + if (c < 0) + { + *errorcodeptr = ERR61; + break; + } + if (c == 0 || (braced && *(++ptr) != '}')) { *errorcodeptr = ERR57; - return 0; + break; } if (negated) @@ -503,7 +582,7 @@ else if (c > bracount) { *errorcodeptr = ERR15; - return 0; + break; } c = bracount - (c - 1); } @@ -532,6 +611,11 @@ else c -= '0'; while ((digitab[ptr[1]] & ctype_digit) != 0) c = c * 10 + *(++ptr) - '0'; + if (c < 0) + { + *errorcodeptr = ERR61; + break; + } if (c < 10 || c <= bracount) { c = -(ESC_REF + c); @@ -627,7 +711,7 @@ else if (c == 0) { *errorcodeptr = ERR2; - return 0; + break; } #ifndef EBCDIC /* ASCII coding */ @@ -703,7 +787,7 @@ if (c == '{') *negptr = TRUE; ptr++; } - for (i = 0; i < sizeof(name) - 1; i++) + for (i = 0; i < (int)sizeof(name) - 1; i++) { c = *(++ptr); if (c == 0) goto ERROR_RETURN; @@ -732,7 +816,7 @@ top = _pcre_utt_size; while (bot < top) { i = (bot + top) >> 1; - c = strcmp(name, _pcre_utt[i].name); + c = strcmp(name, _pcre_utt_names + _pcre_utt[i].name_offset); if (c == 0) { *dptr = _pcre_utt[i].value; @@ -906,6 +990,7 @@ for (; *ptr != 0; ptr++) { while (*(++ptr) != ']') { + if (*ptr == 0) return -1; if (*ptr == '\\') { if (*(++ptr) == 0) return -1; @@ -933,7 +1018,7 @@ for (; *ptr != 0; ptr++) /* An opening parens must now be a real metacharacter */ if (*ptr != '(') continue; - if (ptr[1] != '?') + if (ptr[1] != '?' && ptr[1] != '*') { count++; if (name == NULL && count == lorn) return count; @@ -1061,7 +1146,6 @@ for (;;) { int d; register int op = *cc; - switch (op) { case OP_CBRA: @@ -1150,6 +1234,7 @@ for (;;) case OP_TYPEEXACT: branchlength += GET2(cc,1); + if (cc[3] == OP_PROP || cc[3] == OP_NOTPROP) cc += 2; cc += 4; break; @@ -1258,13 +1343,42 @@ for (;;) code += _pcre_OP_lengths[c]; } - /* In UTF-8 mode, opcodes that are followed by a character may be followed by - a multi-byte character. The length in the table is a minimum, so we have to - arrange to skip the extra bytes. */ + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two bytes of parameters. */ else { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + case OP_TYPEPOSUPTO: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + } + + /* Add in the fixed length from the table */ + code += _pcre_OP_lengths[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed by + a multi-byte character. The length in the table is a minimum, so we have to + arrange to skip the extra bytes. */ + #ifdef SUPPORT_UTF8 if (utf8) switch(c) { @@ -1322,14 +1436,42 @@ for (;;) if (c == OP_XCLASS) code += GET(code, 1); - /* 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 arrange to skip the extra - bytes. */ + /* Otherwise, we can get the item's length from the table, except that for + repeated character types, we have to test for \p and \P, which have an extra + two bytes of parameters. */ else { + switch(c) + { + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSSTAR: + case OP_TYPEPOSPLUS: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + case OP_TYPEPOSUPTO: + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEEXACT: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + } + + /* Add in the fixed length from the table */ + code += _pcre_OP_lengths[c]; + + /* In UTF-8 mode, opcodes that are followed by a character may be followed + by a multi-byte character. The length in the table is a minimum, so we have + to arrange to skip the extra bytes. */ + #ifdef SUPPORT_UTF8 if (utf8) switch(c) { @@ -1401,7 +1543,7 @@ for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE /* For other groups, scan the branches. */ - if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE) + if (c == OP_BRA || c == OP_CBRA || c == OP_ONCE || c == OP_COND) { BOOL empty_branch; if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ @@ -1425,11 +1567,15 @@ for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE switch (c) { - /* Check for quantifiers after a class */ + /* Check for quantifiers after a class. XCLASS is used for classes that + cannot be represented just by a bit map. This includes negated single + high-valued characters. The length in _pcre_OP_lengths[] is zero; the + actual length is stored in the compiled code, so we must update "code" + here. */ #ifdef SUPPORT_UTF8 case OP_XCLASS: - ccode = code + GET(code, 1); + ccode = code += GET(code, 1); goto CHECK_CLASS_REPEAT; #endif @@ -1491,6 +1637,26 @@ for (code = first_significant_code(code + _pcre_OP_lengths[*code], NULL, 0, TRUE case OP_TYPEEXACT: return FALSE; + /* These are going to continue, as they may be empty, but we have to + fudge the length for the \p and \P cases. */ + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPOSSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + case OP_TYPEPOSQUERY: + if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; + break; + + /* Same for these */ + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + case OP_TYPEPOSUPTO: + if (code[3] == OP_PROP || code[3] == OP_NOTPROP) code += 2; + break; + /* End of branch */ case OP_KET: @@ -1607,11 +1773,13 @@ Returns: a value representing the name, or -1 if unknown static int check_posix_name(const uschar *ptr, int len) { +const char *pn = posix_names; register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && - strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; + strncmp((const char *)ptr, pn, len) == 0) return yield; + pn += posix_name_lengths[yield] + 1; yield++; } return -1; @@ -1653,6 +1821,7 @@ 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; @@ -2257,6 +2426,15 @@ for (;; ptr++) */ if (code < last_code) code = last_code; + + /* Paranoid check for integer overflow */ + + if (OFLOW_MAX - *lengthptr < code - last_code) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += code - last_code; DPRINTF(("length=%d added %d c=%c\n", *lengthptr, code - last_code, c)); @@ -2369,6 +2547,11 @@ for (;; ptr++) *ptrptr = ptr; if (lengthptr != NULL) { + if (OFLOW_MAX - *lengthptr < code - last_code) + { + *errorcodeptr = ERR20; + goto FAILED; + } *lengthptr += code - last_code; /* To include callout length */ DPRINTF((">> end branch\n")); } @@ -2431,16 +2614,23 @@ for (;; ptr++) goto FAILED; } - /* If the first character is '^', set the negation flag and skip it. */ + /* If the first character is '^', set the negation flag and skip it. Also, + if the first few characters (either before or after ^) are \Q\E or \E we + skip them too. This makes for compatibility with Perl. */ - if ((c = *(++ptr)) == '^') + negate_class = FALSE; + for (;;) { - negate_class = TRUE; c = *(++ptr); - } - else - { - negate_class = FALSE; + if (c == '\\') + { + if (ptr[1] == 'E') ptr++; + else if (strncmp((const char *)ptr+1, "Q\\E", 3) == 0) ptr += 3; + else break; + } + else if (!negate_class && c == '^') + negate_class = TRUE; + else break; } /* Keep a count of chars with values < 256 so that we can optimize the case @@ -2581,7 +2771,7 @@ for (;; ptr++) 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 + 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 == '\\') @@ -2601,6 +2791,7 @@ for (;; ptr++) else inescq = TRUE; continue; } + else if (-c == ESC_E) continue; /* Ignore orphan \E */ if (c < 0) { @@ -2827,6 +3018,12 @@ for (;; ptr++) oldptr = ptr; + /* Remember \r or \n */ + + if (c == '\r' || c == '\n') cd->external_flags |= PCRE_HASCRORLF; + + /* Check for range */ + if (!inescq && ptr[1] == '-') { int d; @@ -2894,6 +3091,10 @@ for (;; ptr++) if (d == c) goto LONE_SINGLE_CHARACTER; /* A few lines below */ + /* Remember \r or \n */ + + if (d == '\r' || d == '\n') cd->external_flags |= PCRE_HASCRORLF; + /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless matching, we have to use an XCLASS with extra data items. Caseless matching for characters > 127 is available only if UCP support is @@ -3047,12 +3248,34 @@ for (;; ptr++) goto FAILED; } + +/* This code has been disabled because it would mean that \s counts as +an explicit \r or \n reference, and that's not really what is wanted. Now +we set the flag only if there is a literal "\r" or "\n" in the class. */ + +#if 0 + /* Remember whether \r or \n are in this class */ + + if (negate_class) + { + if ((classbits[1] & 0x24) != 0x24) cd->external_flags |= PCRE_HASCRORLF; + } + else + { + if ((classbits[1] & 0x24) != 0) cd->external_flags |= PCRE_HASCRORLF; + } +#endif + + /* 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 - can optimize the negative case only if there were no characters >= 128 - because OP_NOT and the related opcodes like OP_NOTSTAR operate on - single-bytes only. This is an historical hangover. Maybe one day we can - tidy these opcodes to handle multi-byte characters. + less than 256. As long as there were no characters >= 128 and there was no + use of \p or \P, in other words, no use of any XCLASS features, we can + optimize. + + In UTF-8 mode, we can optimize the negative case only if there were no + characters >= 128 because OP_NOT and the related opcodes like OP_NOTSTAR + operate on single-bytes only. This is an historical hangover. Maybe one day + we can tidy these opcodes to handle multi-byte characters. The optimization throws away the bit map. We turn the item into a 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note @@ -3062,10 +3285,8 @@ for (;; ptr++) reqbyte, save the previous value for reinstating. */ #ifdef SUPPORT_UTF8 - if (class_charcount == 1 && - (!utf8 || - (!class_utf8 && (!negate_class || class_lastchar < 128)))) - + if (class_charcount == 1 && !class_utf8 && + (!utf8 || !negate_class || class_lastchar < 128)) #else if (class_charcount == 1) #endif @@ -3337,7 +3558,7 @@ for (;; ptr++) /* All real repeats make it impossible to handle partial matching (maybe one day we will be able to remove this restriction). */ - if (repeat_max != 1) cd->nopartial = TRUE; + if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; /* Combine the op_type with the repeat_type */ @@ -3487,7 +3708,7 @@ for (;; ptr++) /* All real repeats make it impossible to handle partial matching (maybe one day we will be able to remove this restriction). */ - if (repeat_max != 1) cd->nopartial = TRUE; + if (repeat_max != 1) cd->external_flags |= PCRE_NOPARTIAL; if (repeat_min == 0 && repeat_max == -1) *code++ = OP_CRSTAR + repeat_type; @@ -3523,14 +3744,6 @@ for (;; ptr++) 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 @@ -3619,10 +3832,21 @@ for (;; ptr++) if (repeat_min > 1) { /* In the pre-compile phase, we don't actually do the replication. We - just adjust the length as if we had. */ + just adjust the length as if we had. Do some paranoid checks for + potential integer overflow. */ if (lengthptr != NULL) - *lengthptr += (repeat_min - 1)*length_prevgroup; + { + int delta = (repeat_min - 1)*length_prevgroup; + if ((double)(repeat_min - 1)*(double)length_prevgroup > + (double)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } /* This is compiling for real */ @@ -3660,11 +3884,23 @@ for (;; ptr++) /* 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. */ + add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some + paranoid checks to avoid integer overflow. */ 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 */ + { + int delta = repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) - + 2 - 2*LINK_SIZE; /* Last one doesn't nest */ + if ((double)repeat_max * + (double)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) + > (double)INT_MAX || + OFLOW_MAX - *lengthptr < delta) + { + *errorcodeptr = ERR20; + goto FAILED; + } + *lengthptr += delta; + } /* This is compiling for real */ @@ -3816,9 +4052,7 @@ for (;; ptr++) /* ===================================================================*/ /* 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. */ + parenthesis forms. */ case '(': newoptions = options; @@ -3827,7 +4061,46 @@ for (;; ptr++) save_hwm = cd->hwm; reset_bracount = FALSE; - if (*(++ptr) == '?') + /* First deal with various "verbs" that can be introduced by '*'. */ + + if (*(++ptr) == '*' && (cd->ctypes[ptr[1]] & ctype_letter) != 0) + { + int i, namelen; + const char *vn = verbnames; + const uschar *name = ++ptr; + previous = NULL; + while ((cd->ctypes[*++ptr] & ctype_letter) != 0); + if (*ptr == ':') + { + *errorcodeptr = ERR59; /* Not supported */ + goto FAILED; + } + if (*ptr != ')') + { + *errorcodeptr = ERR60; + goto FAILED; + } + namelen = ptr - name; + for (i = 0; i < verbcount; i++) + { + if (namelen == verbs[i].len && + strncmp((char *)name, vn, namelen) == 0) + { + *code = verbs[i].op; + if (*code++ == OP_ACCEPT) cd->had_accept = TRUE; + break; + } + vn += verbs[i].len + 1; + } + if (i < verbcount) continue; + *errorcodeptr = ERR60; + goto FAILED; + } + + /* Deal with the extended parentheses; all are introduced by '?', and the + appearance of any of them means that this is not a capturing group. */ + + else if (*ptr == '?') { int i, set, unset, namelen; int *optset; @@ -4069,8 +4342,14 @@ for (;; ptr++) /* ------------------------------------------------------------ */ case '!': /* Negative lookahead */ - bravalue = OP_ASSERT_NOT; ptr++; + if (*ptr == ')') /* Optimize (?!) */ + { + *code++ = OP_FAIL; + previous = NULL; + continue; + } + bravalue = OP_ASSERT_NOT; break; @@ -4428,7 +4707,7 @@ for (;; ptr++) case 'J': /* Record that it changed in the external options */ *optset |= PCRE_DUPNAMES; - cd->external_options |= PCRE_JCHANGED; + cd->external_flags |= PCRE_JCHANGED; break; case 'i': *optset |= PCRE_CASELESS; break; @@ -4619,23 +4898,29 @@ for (;; ptr++) goto FAILED; } - /* 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. */ + /* In the pre-compile phase, update the length by the length of the group, + less the brackets at either end. Then reduce the compiled code to just a + set of non-capturing brackets so that it doesn't use much memory if it is + duplicated by a quantifier.*/ if (lengthptr != NULL) { + if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) + { + *errorcodeptr = ERR20; + goto FAILED; + } *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; - code++; + *code++ = OP_BRA; PUTINC(code, 0, 1 + LINK_SIZE); *code++ = OP_KET; PUTINC(code, 0, 1 + LINK_SIZE); + break; /* No need to waste time with special character handling */ } /* Otherwise update the main code pointer to the end of the group. */ - else code = tempcode; + code = tempcode; /* For a DEFINE group, required and first character settings are not relevant. */ @@ -4839,6 +5124,11 @@ for (;; ptr++) *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARNC : OP_CHAR; for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; + /* Remember if \r or \n were seen */ + + if (mcbuffer[0] == '\r' || mcbuffer[0] == '\n') + cd->external_flags |= PCRE_HASCRORLF; + /* Set the first and required bytes appropriately. If no previous first byte, set it from this character, but revert to none on a zero repeat. Otherwise, leave the firstbyte value alone, and don't change it on a zero @@ -5121,7 +5411,15 @@ for (;;) *ptrptr = ptr; *firstbyteptr = firstbyte; *reqbyteptr = reqbyte; - if (lengthptr != NULL) *lengthptr += length; + if (lengthptr != NULL) + { + if (OFLOW_MAX - *lengthptr < length) + { + *errorcodeptr = ERR20; + return FALSE; + } + *lengthptr += length; + } return TRUE; } @@ -5430,6 +5728,7 @@ real_pcre *re; int length = 1; /* For final END opcode */ int firstbyte, reqbyte, newline; int errorcode = 0; +int skipatstart = 0; #ifdef SUPPORT_UTF8 BOOL utf8; #endif @@ -5508,13 +5807,55 @@ cd->fcc = tables + fcc_offset; cd->cbits = tables + cbits_offset; cd->ctypes = tables + ctypes_offset; +/* Check for global one-time settings at the start of the pattern, and remember +the offset for later. */ + +while (ptr[skipatstart] == '(' && ptr[skipatstart+1] == '*') + { + int newnl = 0; + int newbsr = 0; + + if (strncmp((char *)(ptr+skipatstart+2), "CR)", 3) == 0) + { skipatstart += 5; newnl = PCRE_NEWLINE_CR; } + else if (strncmp((char *)(ptr+skipatstart+2), "LF)", 3) == 0) + { skipatstart += 5; newnl = PCRE_NEWLINE_LF; } + else if (strncmp((char *)(ptr+skipatstart+2), "CRLF)", 5) == 0) + { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; } + else if (strncmp((char *)(ptr+skipatstart+2), "ANY)", 4) == 0) + { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; } + else if (strncmp((char *)(ptr+skipatstart+2), "ANYCRLF)", 8) == 0) + { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; } + + else if (strncmp((char *)(ptr+skipatstart+2), "BSR_ANYCRLF)", 12) == 0) + { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; } + else if (strncmp((char *)(ptr+skipatstart+2), "BSR_UNICODE)", 12) == 0) + { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; } + + if (newnl != 0) + options = (options & ~PCRE_NEWLINE_BITS) | newnl; + else if (newbsr != 0) + options = (options & ~(PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) | newbsr; + else break; + } + +/* Check validity of \R options. */ + +switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) + { + case 0: + case PCRE_BSR_ANYCRLF: + case PCRE_BSR_UNICODE: + break; + default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; + } + /* Handle different types of newline. The three bits give seven cases. The current code allows for fixed one- or two-byte sequences, plus "any" and "anycrlf". */ -switch (options & (PCRE_NEWLINE_CRLF | PCRE_NEWLINE_ANY)) +switch (options & PCRE_NEWLINE_BITS) { - case 0: newline = NEWLINE; break; /* Compile-time default */ + case 0: newline = NEWLINE; break; /* Build-time default */ case PCRE_NEWLINE_CR: newline = '\r'; break; case PCRE_NEWLINE_LF: newline = '\n'; break; case PCRE_NEWLINE_CR+ @@ -5577,8 +5918,8 @@ 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; +cd->external_flags = 0; /* 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 @@ -5586,6 +5927,7 @@ 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. */ +ptr += skipatstart; code = cworkspace; *code = OP_BRA; (void)compile_regex(cd->external_options, cd->external_options & PCRE_IMS, @@ -5616,14 +5958,16 @@ if (re == NULL) goto PCRE_EARLY_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. */ +/* Put in the magic number, and save the sizes, initial options, internal +flags, 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 = cd->external_options; +re->flags = cd->external_flags; re->dummy1 = 0; re->first_byte = 0; re->req_byte = 0; @@ -5648,21 +5992,22 @@ 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; +cd->had_accept = 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; +ptr = (const uschar *)pattern + skipatstart; code = (uschar *)codestart; *code = OP_BRA; (void)compile_regex(re->options, re->options & PCRE_IMS, &code, &ptr, &errorcode, FALSE, FALSE, 0, &firstbyte, &reqbyte, NULL, cd, NULL); re->top_bracket = cd->bracount; re->top_backref = cd->top_backref; +re->flags = cd->external_flags; -if (cd->nopartial) re->options |= PCRE_NOPARTIAL; +if (cd->had_accept) reqbyte = -1; /* Must disable after (*ACCEPT) */ /* If not reached end of pattern on success, there's an excess bracket. */ @@ -5704,7 +6049,7 @@ if (errorcode != 0) PCRE_EARLY_ERROR_RETURN: *erroroffset = ptr - (const uschar *)pattern; PCRE_EARLY_ERROR_RETURN2: - *errorptr = error_texts[errorcode]; + *errorptr = find_error_text(errorcode); if (errorcodeptr != NULL) *errorcodeptr = errorcode; return NULL; } @@ -5733,10 +6078,10 @@ if ((re->options & PCRE_ANCHORED) == 0) int ch = firstbyte & 255; re->first_byte = ((firstbyte & REQ_CASELESS) != 0 && cd->fcc[ch] == ch)? ch : firstbyte; - re->options |= PCRE_FIRSTSET; + re->flags |= PCRE_FIRSTSET; } else if (is_startline(codestart, 0, cd->backref_map)) - re->options |= PCRE_STARTLINE; + re->flags |= PCRE_STARTLINE; } } @@ -5750,7 +6095,7 @@ if (reqbyte >= 0 && int ch = reqbyte & 255; re->req_byte = ((reqbyte & REQ_CASELESS) != 0 && cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte; - re->options |= PCRE_REQCHSET; + re->flags |= PCRE_REQCHSET; } /* Print out the compiled data if debugging is enabled. This is never the @@ -5761,21 +6106,9 @@ case when building a production library. */ printf("Length = %d top_bracket = %d top_backref = %d\n", length, re->top_bracket, re->top_backref); -if (re->options != 0) - { - printf("%s%s%s%s%s%s%s%s%s\n", - ((re->options & PCRE_NOPARTIAL) != 0)? "nopartial " : "", - ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "", - ((re->options & PCRE_CASELESS) != 0)? "caseless " : "", - ((re->options & PCRE_EXTENDED) != 0)? "extended " : "", - ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "", - ((re->options & PCRE_DOTALL) != 0)? "dotall " : "", - ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "", - ((re->options & PCRE_EXTRA) != 0)? "extra " : "", - ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : ""); - } +printf("Options=%08x\n", re->options); -if ((re->options & PCRE_FIRSTSET) != 0) +if ((re->flags & PCRE_FIRSTSET) != 0) { int ch = re->first_byte & 255; const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? @@ -5784,7 +6117,7 @@ if ((re->options & PCRE_FIRSTSET) != 0) else printf("First char = \\x%02x%s\n", ch, caseless); } -if ((re->options & PCRE_REQCHSET) != 0) +if ((re->flags & PCRE_REQCHSET) != 0) { int ch = re->req_byte & 255; const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? @@ -5801,7 +6134,7 @@ was compiled can be seen. */ if (code - codestart > length) { (pcre_free)(re); - *errorptr = error_texts[ERR23]; + *errorptr = find_error_text(ERR23); *erroroffset = ptr - (uschar *)pattern; if (errorcodeptr != NULL) *errorcodeptr = ERR23; return NULL; diff --git a/src/src/pcre/pcre_config.c b/src/src/pcre/pcre_config.c index ff8cdf89a..131ae6410 100644 --- a/src/src/pcre/pcre_config.c +++ b/src/src/pcre/pcre_config.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_config.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_config.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -43,6 +43,10 @@ POSSIBILITY OF SUCH DAMAGE. /* This module contains the external function pcre_config(). */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -85,6 +89,14 @@ switch (what) *((int *)where) = NEWLINE; break; + case PCRE_CONFIG_BSR: +#ifdef BSR_ANYCRLF + *((int *)where) = 1; +#else + *((int *)where) = 0; +#endif + break; + case PCRE_CONFIG_LINK_SIZE: *((int *)where) = LINK_SIZE; break; diff --git a/src/src/pcre/pcre_exec.c b/src/src/pcre/pcre_exec.c index a27835d74..12703bfa1 100644 --- a/src/src/pcre/pcre_exec.c +++ b/src/src/pcre/pcre_exec.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_exec.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_exec.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE. pattern matching using an NFA algorithm, trying to mimic Perl as closely as possible. There are also some static supporting functions. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #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 */ @@ -55,16 +59,10 @@ possible. There are also some static supporting functions. */ #undef min #undef max -/* 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. */ - -#define EPTR_WORK_SIZE (1000) - /* Flag bits for the match() function */ #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. */ @@ -72,6 +70,14 @@ defined PCRE_ERROR_xxx codes, which are all negative. */ #define MATCH_MATCH 1 #define MATCH_NOMATCH 0 +/* Special internal returns from the match() function. Make them sufficiently +negative to avoid the external error codes. */ + +#define MATCH_COMMIT (-999) +#define MATCH_PRUNE (-998) +#define MATCH_SKIP (-997) +#define MATCH_THEN (-996) + /* Maximum number of ints of offset to save on the stack for recursive calls. If the offset vector is bigger, malloc is used. This should be a multiple of 3, because the offset vector is always a multiple of 3 long. */ @@ -207,15 +213,15 @@ variable instead of being passed in the frame. **************************************************************************** ***************************************************************************/ - -/* Numbers for RMATCH calls */ +/* Numbers for RMATCH calls. When this list is changed, the code at HEAP_RETURN +below must be updated in sync. */ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, - RM41, RM42, RM43, RM44, RM45, RM46, RM47 }; - + RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, + RM51, RM52, RM53, RM54 }; /* These versions of the macros use the stack, as normal. There are debugging versions and production versions. Note that the "rw" argument of RMATCH isn't @@ -386,7 +392,6 @@ Arguments: match_condassert - this is an assertion condition 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 @@ -588,22 +593,16 @@ original_ims = ims; /* Save for resetting on ')' */ 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. */ +When match() is called in other circumstances, don't add to the chain. The +match_cbegroup flag must NOT be used with tail recursion, because the memory +block that is used is on the stack, so a new one may be required for each +match(). */ if ((flags & match_cbegroup) != 0) { - 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; + newptrb.epb_saved_eptr = eptr; + newptrb.epb_prev = eptrb; + eptrb = &newptrb; } /* Now start processing the opcodes. */ @@ -623,6 +622,34 @@ for (;;) switch(op) { + case OP_FAIL: + RRETURN(MATCH_NOMATCH); + + case OP_PRUNE: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM51); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_PRUNE); + + case OP_COMMIT: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM52); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_COMMIT); + + case OP_SKIP: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM53); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + md->start_match_ptr = eptr; /* Pass back current position */ + RRETURN(MATCH_SKIP); + + case OP_THEN: + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, + ims, eptrb, flags, RM54); + if (rrc != MATCH_NOMATCH) RRETURN(rrc); + RRETURN(MATCH_THEN); + /* Handle a capturing bracket. If there is space in the offset vector, save the current subject position in the working slot at the top of the vector. We mustn't change the current values of the data slot, because they may be @@ -664,7 +691,7 @@ for (;;) { RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, eptrb, flags, RM1); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); md->capture_last = save_capture_last; ecode += GET(ecode, 1); } @@ -679,15 +706,22 @@ for (;;) RRETURN(MATCH_NOMATCH); } - /* Insufficient room for saving captured contents. Treat as a non-capturing - bracket. */ + /* FALL THROUGH ... Insufficient room for saving captured contents. Treat + as a non-capturing bracket. */ + + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ DPRINTF(("insufficient capture room: treat as non-capturing\n")); + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + /* VVVVVVVVVVVVVVVVVVVVVVVVV */ + /* Non-capturing 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. */ + turning this into a tail recursion, except in the case when match_cbegroup + is set.*/ case OP_BRA: case OP_SBRA: @@ -695,12 +729,20 @@ for (;;) flags = (op >= OP_SBRA)? match_cbegroup : 0; for (;;) { - if (ecode[GET(ecode, 1)] != OP_ALT) + if (ecode[GET(ecode, 1)] != OP_ALT) /* Final alternative */ { - ecode += _pcre_OP_lengths[*ecode]; - flags |= match_tail_recursed; - DPRINTF(("bracket 0 tail recursion\n")); - goto TAIL_RECURSE; + if (flags == 0) /* Not a possibly empty group */ + { + ecode += _pcre_OP_lengths[*ecode]; + DPRINTF(("bracket 0 tail recursion\n")); + goto TAIL_RECURSE; + } + + /* Possibly empty group; can't use tail recursion. */ + + RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, + eptrb, flags, RM48); + RRETURN(rrc); } /* For non-final alternatives, continue the loop for a NOMATCH result; @@ -708,7 +750,7 @@ for (;;) RMATCH(eptr, ecode + _pcre_OP_lengths[*ecode], offset_top, md, ims, eptrb, flags, RM2); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); ecode += GET(ecode, 1); } /* Control never reaches here. */ @@ -756,7 +798,7 @@ for (;;) ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE + 2); while (*ecode == OP_ALT) ecode += GET(ecode, 1); } - else if (rrc != MATCH_NOMATCH) + else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) { RRETURN(rrc); /* Need braces because of following else */ } @@ -768,25 +810,36 @@ for (;;) } /* 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. */ + we can use tail recursion to avoid using another stack frame, except when + match_cbegroup is required for an unlimited repeat of a possibly empty + group. If the second alternative doesn't exist, we can just plough on. */ if (condition || *ecode == OP_ALT) { ecode += 1 + LINK_SIZE; - flags = match_tail_recursed | ((op == OP_SCOND)? match_cbegroup : 0); - goto TAIL_RECURSE; + if (op == OP_SCOND) /* Possibly empty group */ + { + RMATCH(eptr, ecode, offset_top, md, ims, eptrb, match_cbegroup, RM49); + RRETURN(rrc); + } + else /* Group must match something */ + { + flags = 0; + goto TAIL_RECURSE; + } } - else + else /* Condition false & no 2nd alternative */ { ecode += 1 + LINK_SIZE; } break; - /* End of the pattern. If we are in a top-level recursion, we should - restore the offsets appropriately and continue from after the call. */ + /* End of the pattern, either real or forced. If we are in a top-level + recursion, we should restore the offsets appropriately and continue from + after the call. */ + case OP_ACCEPT: case OP_END: if (md->recursive != NULL && md->recursive->group_num == 0) { @@ -807,7 +860,7 @@ for (;;) if (md->notempty && eptr == mstart) RRETURN(MATCH_NOMATCH); md->end_match_ptr = eptr; /* Record where we ended */ md->end_offset_top = offset_top; /* and how many extracts were taken */ - md->start_match_ptr = mstart; /* and the start (\K can modify) */ + md->start_match_ptr = mstart; /* and the start (\K can modify) */ RRETURN(MATCH_MATCH); /* Change option settings */ @@ -831,7 +884,7 @@ for (;;) RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, RM4); if (rrc == MATCH_MATCH) break; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); ecode += GET(ecode, 1); } while (*ecode == OP_ALT); @@ -858,7 +911,7 @@ for (;;) RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL, 0, RM5); if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH); - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); ecode += GET(ecode,1); } while (*ecode == OP_ALT); @@ -882,7 +935,7 @@ for (;;) { eptr--; if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); - BACKCHAR(eptr) + BACKCHAR(eptr); } } else @@ -995,7 +1048,7 @@ for (;;) (pcre_free)(new_recursive.offset_save); RRETURN(MATCH_MATCH); } - else if (rrc != MATCH_NOMATCH) + else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) { DPRINTF(("Recursion gave error %d\n", rrc)); RRETURN(rrc); @@ -1029,10 +1082,9 @@ for (;;) do { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, - eptrb, 0, RM7); + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM7); if (rrc == MATCH_MATCH) break; - if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc); ecode += GET(ecode,1); } while (*ecode == OP_ALT); @@ -1075,11 +1127,10 @@ for (;;) if (*ecode == OP_KETRMIN) { - RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, - RM8); + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM8); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode = prev; - flags = match_tail_recursed; + flags = 0; goto TAIL_RECURSE; } else /* OP_KETRMAX */ @@ -1087,7 +1138,7 @@ for (;;) RMATCH(eptr, prev, offset_top, md, ims, eptrb, match_cbegroup, RM9); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += 1 + LINK_SIZE; - flags = match_tail_recursed; + flags = 0; goto TAIL_RECURSE; } /* Control never gets here */ @@ -1218,17 +1269,21 @@ for (;;) /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. In the second case, we can use - tail recursion to avoid using another stack frame. */ + tail recursion to avoid using another stack frame, unless we have an + unlimited repeat of a group that can match an empty string. */ flags = (*prev >= OP_SBRA)? match_cbegroup : 0; if (*ecode == OP_KETRMIN) { - RMATCH(eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0, - RM12); + RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0, RM12); if (rrc != MATCH_NOMATCH) RRETURN(rrc); + if (flags != 0) /* Could match an empty string */ + { + RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM50); + RRETURN(rrc); + } ecode = prev; - flags |= match_tail_recursed; goto TAIL_RECURSE; } else /* OP_KETRMAX */ @@ -1236,7 +1291,7 @@ for (;;) RMATCH(eptr, prev, offset_top, md, ims, eptrb, flags, RM13); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += 1 + LINK_SIZE; - flags = match_tail_recursed; + flags = 0; goto TAIL_RECURSE; } /* Control never gets here */ @@ -1473,12 +1528,16 @@ for (;;) case 0x000d: if (eptr < md->end_subject && *eptr == 0x0a) eptr++; break; + case 0x000a: + break; + case 0x000b: case 0x000c: case 0x0085: case 0x2028: case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } ecode++; @@ -2035,7 +2094,7 @@ for (;;) RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM21); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr) + if (utf8) BACKCHAR(eptr); } RRETURN(MATCH_NOMATCH); } @@ -2901,12 +2960,16 @@ for (;;) case 0x000d: if (eptr < md->end_subject && *eptr == 0x0a) eptr++; break; + case 0x000a: + break; + case 0x000b: case 0x000c: case 0x0085: case 0x2028: case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } } @@ -3040,9 +3103,9 @@ for (;;) for (i = 1; i <= min; i++) { if (eptr >= md->end_subject || - (*eptr < 128 && (md->ctypes[*eptr++] & ctype_space) != 0)) + (*eptr < 128 && (md->ctypes[*eptr] & ctype_space) != 0)) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); } break; @@ -3060,9 +3123,9 @@ for (;;) for (i = 1; i <= min; i++) { if (eptr >= md->end_subject || - (*eptr < 128 && (md->ctypes[*eptr++] & ctype_word) != 0)) + (*eptr < 128 && (md->ctypes[*eptr] & ctype_word) != 0)) RRETURN(MATCH_NOMATCH); - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + while (++eptr < md->end_subject && (*eptr & 0xc0) == 0x80); } break; @@ -3119,9 +3182,12 @@ for (;;) if (eptr < md->end_subject && *eptr == 0x0a) eptr++; break; case 0x000a: + break; + case 0x000b: case 0x000c: case 0x0085: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } } @@ -3373,11 +3439,14 @@ for (;;) if (eptr < md->end_subject && *eptr == 0x0a) eptr++; break; case 0x000a: + break; + case 0x000b: case 0x000c: case 0x0085: case 0x2028: case 0x2029: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } break; @@ -3529,10 +3598,14 @@ for (;;) case 0x000d: if (eptr < md->end_subject && *eptr == 0x0a) eptr++; break; + case 0x000a: + break; + case 0x000b: case 0x000c: case 0x0085: + if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } break; @@ -3704,7 +3777,7 @@ for (;;) RMATCH(eptr, ecode, offset_top, md, ims, eptrb, 0, RM44); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (eptr-- == pp) break; /* Stop if tried at original pos */ - BACKCHAR(eptr); + if (utf8) BACKCHAR(eptr); } } @@ -3743,9 +3816,9 @@ for (;;) for (;;) /* Move back over one extended */ { int len = 1; - BACKCHAR(eptr); if (!utf8) c = *eptr; else { + BACKCHAR(eptr); GETCHARLEN(c, eptr, len); } prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script); @@ -3766,11 +3839,6 @@ for (;;) switch(ctype) { case OP_ANY: - - /* Special code is required for UTF8, but when the maximum is - unlimited we don't need it, so we repeat the non-UTF8 code. This is - probably worth it, because .* is quite a common idiom. */ - if (max < INT_MAX) { if ((ims & PCRE_DOTALL) == 0) @@ -3803,15 +3871,12 @@ for (;;) { if (eptr >= md->end_subject || IS_NEWLINE(eptr)) break; eptr++; + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } - break; } else { - c = max - min; - if (c > (unsigned int)(md->end_subject - eptr)) - c = md->end_subject - eptr; - eptr += c; + eptr = md->end_subject; } } break; @@ -3838,8 +3903,10 @@ for (;;) } else { - if (c != 0x000a && c != 0x000b && c != 0x000c && - c != 0x0085 && c != 0x2028 && c != 0x2029) + if (c != 0x000a && + (md->bsr_anycrlf || + (c != 0x000b && c != 0x000c && + c != 0x0085 && c != 0x2028 && c != 0x2029))) break; eptr += len; } @@ -3992,7 +4059,7 @@ for (;;) } } else -#endif +#endif /* SUPPORT_UTF8 */ /* Not UTF-8 mode */ { @@ -4029,7 +4096,9 @@ for (;;) } else { - if (c != 0x000a && c != 0x000b && c != 0x000c && c != 0x0085) + if (c != 0x000a && + (md->bsr_anycrlf || + (c != 0x000b && c != 0x000c && c != 0x0085))) break; eptr++; } @@ -4179,11 +4248,17 @@ HEAP_RETURN: switch (frame->Xwhere) { LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) - LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16) - LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24) - LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32) - LBL(33) LBL(34) LBL(35) LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) - LBL(41) LBL(42) LBL(43) LBL(44) LBL(45) LBL(46) LBL(47) + LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17) + LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33) + LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52) + LBL(53) LBL(54) +#ifdef SUPPORT_UTF8 + LBL(16) LBL(18) LBL(20) LBL(21) LBL(22) LBL(23) LBL(28) LBL(30) + LBL(32) LBL(34) LBL(42) LBL(46) +#ifdef SUPPORT_UCP + LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) +#endif /* SUPPORT_UCP */ +#endif /* SUPPORT_UTF8 */ default: DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere)); return PCRE_ERROR_INTERNAL; @@ -4300,7 +4375,6 @@ const uschar *start_bits = NULL; 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; @@ -4363,7 +4437,7 @@ if (re->magic_number != MAGIC_NUMBER) /* Set up other data */ anchored = ((re->options | options) & PCRE_ANCHORED) != 0; -startline = (re->options & PCRE_STARTLINE) != 0; +startline = (re->flags & PCRE_STARTLINE) != 0; firstline = (re->options & PCRE_FIRSTLINE) != 0; /* The code starts after the real_pcre block and the capture name table. */ @@ -4386,16 +4460,41 @@ md->partial = (options & PCRE_PARTIAL) != 0; 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; +/* Handle different \R options. */ + +switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) + { + case 0: + if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) + md->bsr_anycrlf = (re->options & PCRE_BSR_ANYCRLF) != 0; + else +#ifdef BSR_ANYCRLF + md->bsr_anycrlf = TRUE; +#else + md->bsr_anycrlf = FALSE; +#endif + break; + + case PCRE_BSR_ANYCRLF: + md->bsr_anycrlf = TRUE; + break; + + case PCRE_BSR_UNICODE: + md->bsr_anycrlf = FALSE; + break; + + default: return PCRE_ERROR_BADNEWLINE; + } + /* Handle different types of newline. The three bits give eight cases. If nothing is set at run time, whatever was used at compile time applies. */ -switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) & - PCRE_NEWLINE_BITS) +switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : + (pcre_uint32)options) & PCRE_NEWLINE_BITS) { case 0: newline = NEWLINE; break; /* Compile-time default */ case PCRE_NEWLINE_CR: newline = '\r'; break; @@ -4434,7 +4533,7 @@ else /* Partial matching is supported only for a restricted set of regexes at the moment. */ -if (md->partial && (re->options & PCRE_NOPARTIAL) != 0) +if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0) return PCRE_ERROR_BADPARTIAL; /* Check a UTF-8 string if required. Unfortunately there's no way of passing @@ -4511,7 +4610,7 @@ studied, there may be a bitmap of possible first characters. */ if (!anchored) { - if ((re->options & PCRE_FIRSTSET) != 0) + if ((re->flags & PCRE_FIRSTSET) != 0) { first_byte = re->first_byte & 255; if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE) @@ -4526,7 +4625,7 @@ if (!anchored) /* For anchored or unanchored matches, there may be a "last known required character" set. */ -if ((re->options & PCRE_REQCHSET) != 0) +if ((re->flags & PCRE_REQCHSET) != 0) { req_byte = re->req_byte & 255; req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0; @@ -4542,6 +4641,7 @@ the loop runs just once. */ for(;;) { USPTR save_end_subject = end_subject; + USPTR new_start_match; /* Reset the maximum number of extractions we might see. */ @@ -4682,15 +4782,48 @@ for(;;) /* OK, we can now run the match. */ - md->start_match_ptr = start_match; /* Insurance */ + md->start_match_ptr = start_match; md->match_call_count = 0; - md->eptrn = 0; /* Next free eptrchain slot */ - rc = match(start_match, md->start_code, start_match, 2, md, - ims, NULL, 0, 0); + rc = match(start_match, md->start_code, start_match, 2, md, ims, NULL, 0, 0); + + switch(rc) + { + /* NOMATCH and PRUNE advance by one character. THEN at this level acts + exactly like PRUNE. */ + + case MATCH_NOMATCH: + case MATCH_PRUNE: + case MATCH_THEN: + new_start_match = start_match + 1; +#ifdef SUPPORT_UTF8 + if (utf8) + while(new_start_match < end_subject && (*new_start_match & 0xc0) == 0x80) + new_start_match++; +#endif + break; + + /* SKIP passes back the next starting point explicitly. */ - /* Any return other than MATCH_NOMATCH breaks the loop. */ + case MATCH_SKIP: + new_start_match = md->start_match_ptr; + break; + + /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */ + + case MATCH_COMMIT: + rc = MATCH_NOMATCH; + goto ENDLOOP; - if (rc != MATCH_NOMATCH) break; + /* Any other return is some kind of error. */ + + default: + goto ENDLOOP; + } + + /* Control reaches here for the various types of "no match at this point" + result. Reset the code to MATCH_NOMATCH for subsequent checking. */ + + rc = MATCH_NOMATCH; /* 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, @@ -4698,30 +4831,26 @@ for(;;) if (firstline && IS_NEWLINE(start_match)) break; - /* Advance the match position by one character. */ + /* Advance to new matching position */ - start_match++; -#ifdef SUPPORT_UTF8 - if (utf8) - while(start_match < end_subject && (*start_match & 0xc0) == 0x80) - start_match++; -#endif + start_match = new_start_match; /* 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 or - ANYCRLF, and we are now at a LF, advance the match position by one more - character. */ + /* If we have just passed a CR and we are now at a LF, and the pattern does + not contain any explicit matches for \r or \n, and the newline option is CRLF + or ANY or ANYCRLF, advance the match position by one more character. */ if (start_match[-1] == '\r' && - (md->nltype == NLTYPE_ANY || - md->nltype == NLTYPE_ANYCRLF || - md->nllen == 2) && - start_match < end_subject && - *start_match == '\n') + start_match < end_subject && + *start_match == '\n' && + (re->flags & PCRE_HASCRORLF) == 0 && + (md->nltype == NLTYPE_ANY || + md->nltype == NLTYPE_ANYCRLF || + md->nllen == 2)) start_match++; } /* End of for(;;) "bumpalong" loop */ @@ -4731,7 +4860,7 @@ for(;;) /* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping conditions is true: -(1) The pattern is anchored; +(1) The pattern is anchored or the match was failed by (*COMMIT); (2) We are past the end of the subject; @@ -4746,6 +4875,8 @@ 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. */ +ENDLOOP: + if (rc == MATCH_MATCH) { if (using_temporary_offsets) diff --git a/src/src/pcre/pcre_fullinfo.c b/src/src/pcre/pcre_fullinfo.c index c17f3d72b..797241dd5 100644 --- a/src/src/pcre/pcre_fullinfo.c +++ b/src/src/pcre/pcre_fullinfo.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_fullinfo.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_fullinfo.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE. information about a compiled pattern. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -108,8 +112,8 @@ switch (what) case PCRE_INFO_FIRSTBYTE: *((int *)where) = - ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte : - ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; + ((re->flags & PCRE_FIRSTSET) != 0)? re->first_byte : + ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; break; /* Make sure we pass back the pointer to the bit vector in the external @@ -123,7 +127,7 @@ switch (what) case PCRE_INFO_LASTLITERAL: *((int *)where) = - ((re->options & PCRE_REQCHSET) != 0)? re->req_byte : -1; + ((re->flags & PCRE_REQCHSET) != 0)? re->req_byte : -1; break; case PCRE_INFO_NAMEENTRYSIZE: @@ -143,11 +147,15 @@ switch (what) break; case PCRE_INFO_OKPARTIAL: - *((int *)where) = (re->options & PCRE_NOPARTIAL) == 0; + *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0; break; case PCRE_INFO_JCHANGED: - *((int *)where) = (re->options & PCRE_JCHANGED) != 0; + *((int *)where) = (re->flags & PCRE_JCHANGED) != 0; + break; + + case PCRE_INFO_HASCRORLF: + *((int *)where) = (re->flags & PCRE_HASCRORLF) != 0; break; default: return PCRE_ERROR_BADOPTION; diff --git a/src/src/pcre/pcre_get.c b/src/src/pcre/pcre_get.c index 3added96d..451b6d981 100644 --- a/src/src/pcre/pcre_get.c +++ b/src/src/pcre/pcre_get.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_get.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_get.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -45,6 +45,10 @@ from the subject string after a regex match has succeeded. The original idea for these functions came from Scott Wimer. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -187,7 +191,7 @@ const real_pcre *re = (const real_pcre *)code; int entrysize; char *first, *last; uschar *entry; -if ((re->options & (PCRE_DUPNAMES | PCRE_JCHANGED)) == 0) +if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre_get_stringnumber(code, stringname); entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last); if (entrysize <= 0) return entrysize; diff --git a/src/src/pcre/pcre_globals.c b/src/src/pcre/pcre_globals.c index ee3707d9d..002a5779f 100644 --- a/src/src/pcre/pcre_globals.c +++ b/src/src/pcre/pcre_globals.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_globals.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_globals.c,v 1.6 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -48,6 +48,10 @@ indirection. These values can be changed by the caller, but are shared between all threads. However, when compiling for Virtual Pascal, things are done differently, and global variables are not used (see pcre.in). */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" #ifndef VPCOMPAT diff --git a/src/src/pcre/pcre_internal.h b/src/src/pcre/pcre_internal.h index 94b07bed3..8f4029c33 100644 --- a/src/src/pcre/pcre_internal.h +++ b/src/src/pcre/pcre_internal.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_internal.h,v 1.6 2007/06/29 08:49:17 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_internal.h,v 1.7 2007/11/12 13:02:19 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -69,10 +69,6 @@ be absolutely sure we get our version. */ #endif -/* Get the definitions provided by running "configure" */ - -#include "config.h" - /* Standard C headers plus the external interface definition. The only time setjmp and stdarg are used is when NO_RECURSE is set. */ @@ -114,7 +110,7 @@ PCRE_EXP_DATA_DEFN only if they are not already set. */ #ifndef PCRE_EXP_DECL # ifdef _WIN32 -# ifdef DLL_EXPORT +# ifndef PCRE_STATIC # define PCRE_EXP_DECL extern __declspec(dllexport) # define PCRE_EXP_DEFN __declspec(dllexport) # define PCRE_EXP_DATA_DEFN __declspec(dllexport) @@ -123,7 +119,6 @@ PCRE_EXP_DATA_DEFN only if they are not already set. */ # define PCRE_EXP_DEFN # define PCRE_EXP_DATA_DEFN # endif -# # else # ifdef __cplusplus # define PCRE_EXP_DECL extern "C" @@ -365,7 +360,9 @@ capturing parenthesis numbers in back references. */ /* When UTF-8 encoding is being used, a character is no longer just a single byte. The macros for character handling generate simple sequences when used in -byte-mode, and more complicated ones for UTF-8 characters. */ +byte-mode, and more complicated ones for UTF-8 characters. BACKCHAR should +never be called in byte mode. To make sure it can never even appear when UTF-8 +support is omitted, we don't even define it. */ #ifndef SUPPORT_UTF8 #define GETCHAR(c, eptr) c = *eptr; @@ -373,7 +370,7 @@ byte-mode, and more complicated ones for UTF-8 characters. */ #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARINCTEST(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; -#define BACKCHAR(eptr) +/* #define BACKCHAR(eptr) */ #else /* SUPPORT_UTF8 */ @@ -466,9 +463,10 @@ if there are extra bytes. This is called when we know we are in UTF-8 mode. */ } /* If the pointer is not at the start of a character, move it back until -it is. Called only in UTF-8 mode. */ +it is. This is called only in UTF-8 mode - we don't put a test within the macro +because almost all calls are already within a block of UTF-8 only code. */ -#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--; +#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr-- #endif @@ -485,17 +483,16 @@ Standard C system should have one. */ #define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) -/* Private options flags start at the most significant end of the four bytes. -The public options defined in pcre.h start at the least significant end. Make -sure they don't overlap! The bits are getting a bit scarce now -- when we run -out, there is a dummy word in the structure that could be used for the private -bits. */ +/* Private flags containing information about the compiled regex. They used to +live at the top end of the options word, but that got almost full, so now they +are in a 16-bit flags word. */ -#define PCRE_NOPARTIAL 0x80000000 /* can't use partial with this regex */ -#define PCRE_FIRSTSET 0x40000000 /* first_byte is set */ -#define PCRE_REQCHSET 0x20000000 /* req_byte is set */ -#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ -#define PCRE_JCHANGED 0x08000000 /* j option changes within regex */ +#define PCRE_NOPARTIAL 0x0001 /* can't use partial with this regex */ +#define PCRE_FIRSTSET 0x0002 /* first_byte is set */ +#define PCRE_REQCHSET 0x0004 /* req_byte is set */ +#define PCRE_STARTLINE 0x0008 /* start after \n for multiline */ +#define PCRE_JCHANGED 0x0010 /* j option used in regex */ +#define PCRE_HASCRORLF 0x0020 /* explicit \r or \n in pattern */ /* Options for the "extra" block produced by pcre_study(). */ @@ -511,15 +508,16 @@ time, run time, or study time, respectively. */ (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_BITS) + PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \ - PCRE_PARTIAL|PCRE_NEWLINE_BITS) + PCRE_PARTIAL|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) #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_BITS) + PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_BITS| \ + PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) #define PUBLIC_STUDY_OPTIONS 0 /* None defined */ @@ -612,14 +610,9 @@ enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_V, ESC_v, 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 +/* Opcode table: 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. -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. */ @@ -746,7 +739,7 @@ enum { as there's a test for >= ONCE for a subpattern that isn't an assertion. */ OP_ONCE, /* 92 Atomic group */ - OP_BRA, /* 83 Start of non-capturing bracket */ + OP_BRA, /* 93 Start of non-capturing bracket */ OP_CBRA, /* 94 Start of capturing bracket */ OP_COND, /* 95 Conditional group */ @@ -762,7 +755,19 @@ enum { OP_DEF, /* 101 The DEFINE condition */ OP_BRAZERO, /* 102 These two must remain together and in this */ - OP_BRAMINZERO /* 103 order. */ + OP_BRAMINZERO, /* 103 order. */ + + /* These are backtracking control verbs */ + + OP_PRUNE, /* 104 */ + OP_SKIP, /* 105 */ + OP_THEN, /* 106 */ + OP_COMMIT, /* 107 */ + + /* These are forced failure and success verbs */ + + OP_FAIL, /* 108 */ + OP_ACCEPT /* 109 */ }; @@ -785,8 +790,9 @@ for debugging. The macro is referenced only in pcre_printint.c. */ "class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ "AssertB", "AssertB not", "Reverse", \ - "Once", "Bra 0", "Bra", "Cond", "SBra 0", "SBra", "SCond", \ - "Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero" + "Once", "Bra", "CBra", "Cond", "SBra", "SCBra", "SCond", \ + "Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero", \ + "*PRUNE", "*SKIP", "*THEN", "*COMMIT", "*FAIL", "*ACCEPT" /* This macro defines the length of fixed length operations in the compiled @@ -850,6 +856,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */ 3, /* RREF */ \ 1, /* DEF */ \ 1, 1, /* BRAZERO, BRAMINZERO */ \ + 1, 1, 1, 1, /* PRUNE, SKIP, THEN, COMMIT, */ \ + 1, 1 /* FAIL, ACCEPT */ /* A magic value for OP_RREF to indicate the "any recursion" condition. */ @@ -864,7 +872,8 @@ enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, 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, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58 }; + ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, + ERR60, ERR61 }; /* 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 @@ -886,9 +895,9 @@ NOTE NOTE NOTE: typedef struct real_pcre { pcre_uint32 magic_number; pcre_uint32 size; /* Total that was malloced */ - pcre_uint32 options; - pcre_uint32 dummy1; /* For future use, maybe */ - + pcre_uint32 options; /* Public options */ + pcre_uint16 flags; /* Private flags */ + pcre_uint16 dummy1; /* For future use */ pcre_uint16 top_bracket; pcre_uint16 top_backref; pcre_uint16 first_byte; @@ -931,8 +940,9 @@ typedef struct compile_data { int top_backref; /* Maximum back reference */ unsigned int backref_map; /* Bitmap of low back refs */ int external_options; /* External (initial) options */ + int external_flags; /* External flag bits to be set */ int req_varyopt; /* "After variable item" flag for reqbyte */ - BOOL nopartial; /* Set TRUE if partial won't work */ + BOOL had_accept; /* (*ACCEPT) encountered */ int nltype; /* Newline type */ int nllen; /* Newline string length */ uschar nl[4]; /* Newline string when fixed length */ @@ -991,6 +1001,7 @@ typedef struct match_data { BOOL notempty; /* Empty string match not wanted */ BOOL partial; /* PARTIAL flag */ BOOL hitend; /* Hit the end of the subject at some point */ + BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */ const uschar *start_code; /* For use when recursing */ USPTR start_subject; /* Start of the subject string */ USPTR end_subject; /* End of the subject string */ @@ -1055,10 +1066,12 @@ total length. */ #define tables_length (ctypes_offset + 256) /* Layout of the UCP type table that translates property names into types and -codes. */ +codes. Each entry used to point directly to a name, but to reduce the number of +relocations in shared libraries, it now has an offset into a single string +instead. */ typedef struct { - const char *name; + pcre_uint16 name_offset; pcre_uint16 type; pcre_uint16 value; } ucp_type_table; @@ -1076,6 +1089,7 @@ extern const uschar _pcre_utf8_table4[]; extern const int _pcre_utf8_table1_size; +extern const char _pcre_utt_names[]; extern const ucp_type_table _pcre_utt[]; extern const int _pcre_utt_size; diff --git a/src/src/pcre/pcre_maketables.c b/src/src/pcre/pcre_maketables.c index 6209c25dc..563f8745c 100644 --- a/src/src/pcre/pcre_maketables.c +++ b/src/src/pcre/pcre_maketables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_maketables.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_maketables.c,v 1.6 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -47,7 +47,10 @@ compilation of dftables.c, in which case the macro DFTABLES is defined. */ #ifndef DFTABLES -#include "pcre_internal.h" +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +# include "pcre_internal.h" #endif diff --git a/src/src/pcre/pcre_newline.c b/src/src/pcre/pcre_newline.c index bf0ade5ae..c71dbafba 100644 --- a/src/src/pcre/pcre_newline.c +++ b/src/src/pcre/pcre_newline.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_newline.c,v 1.2 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_newline.c,v 1.3 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -49,6 +49,10 @@ and NLTYPE_ANY. The full list of Unicode newline characters is taken from http://unicode.org/unicode/reports/tr18/. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -126,12 +130,16 @@ _pcre_was_newline(const uschar *ptr, int type, const uschar *startptr, { int c; ptr--; +#ifdef SUPPORT_UTF8 if (utf8) { BACKCHAR(ptr); GETCHAR(c, ptr); } else c = *ptr; +#else /* no UTF-8 support */ +c = *ptr; +#endif /* SUPPORT_UTF8 */ if (type == NLTYPE_ANYCRLF) switch(c) { diff --git a/src/src/pcre/pcre_printint.src b/src/src/pcre/pcre_printint.src index 7e2837b72..b32d3fbd1 100644 --- a/src/src/pcre/pcre_printint.src +++ b/src/src/pcre/pcre_printint.src @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_printint.src,v 1.3 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_printint.src,v 1.4 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -124,11 +124,11 @@ get_ucpname(int ptype, int pvalue) { #ifdef SUPPORT_UCP int i; -for (i = _pcre_utt_size; i >= 0; i--) +for (i = _pcre_utt_size - 1; i >= 0; i--) { if (ptype == _pcre_utt[i].type && pvalue == _pcre_utt[i].value) break; } -return (i >= 0)? _pcre_utt[i].name : "??"; +return (i >= 0)? _pcre_utt_names + _pcre_utt[i].name_offset : "??"; #else /* It gets harder and harder to shut off unwanted compiler warnings. */ ptype = ptype * pvalue; diff --git a/src/src/pcre/pcre_study.c b/src/src/pcre/pcre_study.c index 8858f7f40..6848a1967 100644 --- a/src/src/pcre/pcre_study.c +++ b/src/src/pcre/pcre_study.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_study.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_study.c,v 1.6 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE. supporting functions. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -525,7 +529,8 @@ code = (uschar *)re + re->name_table_offset + a multiline pattern that matches only at "line starts", no further processing at present. */ -if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) +if ((re->options & PCRE_ANCHORED) != 0 || + (re->flags & (PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) return NULL; /* Set the character tables in the block that is passed around */ diff --git a/src/src/pcre/pcre_tables.c b/src/src/pcre/pcre_tables.c index 1c2f1cd06..530e44038 100644 --- a/src/src/pcre/pcre_tables.c +++ b/src/src/pcre/pcre_tables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_tables.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_tables.c,v 1.6 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -46,6 +46,10 @@ uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name clashes with the library. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -85,115 +89,228 @@ const uschar _pcre_utf8_table4[] = { 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 }; -/* This table translates Unicode property names into type and code values. It -is searched by binary chop, so must be in collating sequence of name. */ +/* The pcre_utt[] table below translates Unicode property names into type and +code values. It is searched by binary chop, so must be in collating sequence of +name. Originally, the table contained pointers to the name strings in the first +field of each entry. However, that leads to a large number of relocations when +a shared library is dynamically loaded. A significant reduction is made by +putting all the names into a single, large string and then using offsets in the +table itself. Maintenance is more error-prone, but frequent changes to this +data is unlikely. */ + +const char _pcre_utt_names[] = + "Any\0" + "Arabic\0" + "Armenian\0" + "Balinese\0" + "Bengali\0" + "Bopomofo\0" + "Braille\0" + "Buginese\0" + "Buhid\0" + "C\0" + "Canadian_Aboriginal\0" + "Cc\0" + "Cf\0" + "Cherokee\0" + "Cn\0" + "Co\0" + "Common\0" + "Coptic\0" + "Cs\0" + "Cuneiform\0" + "Cypriot\0" + "Cyrillic\0" + "Deseret\0" + "Devanagari\0" + "Ethiopic\0" + "Georgian\0" + "Glagolitic\0" + "Gothic\0" + "Greek\0" + "Gujarati\0" + "Gurmukhi\0" + "Han\0" + "Hangul\0" + "Hanunoo\0" + "Hebrew\0" + "Hiragana\0" + "Inherited\0" + "Kannada\0" + "Katakana\0" + "Kharoshthi\0" + "Khmer\0" + "L\0" + "L&\0" + "Lao\0" + "Latin\0" + "Limbu\0" + "Linear_B\0" + "Ll\0" + "Lm\0" + "Lo\0" + "Lt\0" + "Lu\0" + "M\0" + "Malayalam\0" + "Mc\0" + "Me\0" + "Mn\0" + "Mongolian\0" + "Myanmar\0" + "N\0" + "Nd\0" + "New_Tai_Lue\0" + "Nko\0" + "Nl\0" + "No\0" + "Ogham\0" + "Old_Italic\0" + "Old_Persian\0" + "Oriya\0" + "Osmanya\0" + "P\0" + "Pc\0" + "Pd\0" + "Pe\0" + "Pf\0" + "Phags_Pa\0" + "Phoenician\0" + "Pi\0" + "Po\0" + "Ps\0" + "Runic\0" + "S\0" + "Sc\0" + "Shavian\0" + "Sinhala\0" + "Sk\0" + "Sm\0" + "So\0" + "Syloti_Nagri\0" + "Syriac\0" + "Tagalog\0" + "Tagbanwa\0" + "Tai_Le\0" + "Tamil\0" + "Telugu\0" + "Thaana\0" + "Thai\0" + "Tibetan\0" + "Tifinagh\0" + "Ugaritic\0" + "Yi\0" + "Z\0" + "Zl\0" + "Zp\0" + "Zs\0"; const ucp_type_table _pcre_utt[] = { - { "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 }, - { "Buginese", PT_SC, ucp_Buginese }, - { "Buhid", PT_SC, ucp_Buhid }, - { "C", PT_GC, ucp_C }, - { "Canadian_Aboriginal", PT_SC, ucp_Canadian_Aboriginal }, - { "Cc", PT_PC, ucp_Cc }, - { "Cf", PT_PC, ucp_Cf }, - { "Cherokee", PT_SC, ucp_Cherokee }, - { "Cn", PT_PC, ucp_Cn }, - { "Co", PT_PC, ucp_Co }, - { "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 }, - { "Devanagari", PT_SC, ucp_Devanagari }, - { "Ethiopic", PT_SC, ucp_Ethiopic }, - { "Georgian", PT_SC, ucp_Georgian }, - { "Glagolitic", PT_SC, ucp_Glagolitic }, - { "Gothic", PT_SC, ucp_Gothic }, - { "Greek", PT_SC, ucp_Greek }, - { "Gujarati", PT_SC, ucp_Gujarati }, - { "Gurmukhi", PT_SC, ucp_Gurmukhi }, - { "Han", PT_SC, ucp_Han }, - { "Hangul", PT_SC, ucp_Hangul }, - { "Hanunoo", PT_SC, ucp_Hanunoo }, - { "Hebrew", PT_SC, ucp_Hebrew }, - { "Hiragana", PT_SC, ucp_Hiragana }, - { "Inherited", PT_SC, ucp_Inherited }, - { "Kannada", PT_SC, ucp_Kannada }, - { "Katakana", PT_SC, ucp_Katakana }, - { "Kharoshthi", PT_SC, ucp_Kharoshthi }, - { "Khmer", PT_SC, ucp_Khmer }, - { "L", PT_GC, ucp_L }, - { "L&", PT_LAMP, 0 }, - { "Lao", PT_SC, ucp_Lao }, - { "Latin", PT_SC, ucp_Latin }, - { "Limbu", PT_SC, ucp_Limbu }, - { "Linear_B", PT_SC, ucp_Linear_B }, - { "Ll", PT_PC, ucp_Ll }, - { "Lm", PT_PC, ucp_Lm }, - { "Lo", PT_PC, ucp_Lo }, - { "Lt", PT_PC, ucp_Lt }, - { "Lu", PT_PC, ucp_Lu }, - { "M", PT_GC, ucp_M }, - { "Malayalam", PT_SC, ucp_Malayalam }, - { "Mc", PT_PC, ucp_Mc }, - { "Me", PT_PC, ucp_Me }, - { "Mn", PT_PC, ucp_Mn }, - { "Mongolian", PT_SC, ucp_Mongolian }, - { "Myanmar", PT_SC, ucp_Myanmar }, - { "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 }, - { "Old_Italic", PT_SC, ucp_Old_Italic }, - { "Old_Persian", PT_SC, ucp_Old_Persian }, - { "Oriya", PT_SC, ucp_Oriya }, - { "Osmanya", PT_SC, ucp_Osmanya }, - { "P", PT_GC, ucp_P }, - { "Pc", PT_PC, ucp_Pc }, - { "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 }, - { "Runic", PT_SC, ucp_Runic }, - { "S", PT_GC, ucp_S }, - { "Sc", PT_PC, ucp_Sc }, - { "Shavian", PT_SC, ucp_Shavian }, - { "Sinhala", PT_SC, ucp_Sinhala }, - { "Sk", PT_PC, ucp_Sk }, - { "Sm", PT_PC, ucp_Sm }, - { "So", PT_PC, ucp_So }, - { "Syloti_Nagri", PT_SC, ucp_Syloti_Nagri }, - { "Syriac", PT_SC, ucp_Syriac }, - { "Tagalog", PT_SC, ucp_Tagalog }, - { "Tagbanwa", PT_SC, ucp_Tagbanwa }, - { "Tai_Le", PT_SC, ucp_Tai_Le }, - { "Tamil", PT_SC, ucp_Tamil }, - { "Telugu", PT_SC, ucp_Telugu }, - { "Thaana", PT_SC, ucp_Thaana }, - { "Thai", PT_SC, ucp_Thai }, - { "Tibetan", PT_SC, ucp_Tibetan }, - { "Tifinagh", PT_SC, ucp_Tifinagh }, - { "Ugaritic", PT_SC, ucp_Ugaritic }, - { "Yi", PT_SC, ucp_Yi }, - { "Z", PT_GC, ucp_Z }, - { "Zl", PT_PC, ucp_Zl }, - { "Zp", PT_PC, ucp_Zp }, - { "Zs", PT_PC, ucp_Zs } + { 0, PT_ANY, 0 }, + { 4, PT_SC, ucp_Arabic }, + { 11, PT_SC, ucp_Armenian }, + { 20, PT_SC, ucp_Balinese }, + { 29, PT_SC, ucp_Bengali }, + { 37, PT_SC, ucp_Bopomofo }, + { 46, PT_SC, ucp_Braille }, + { 54, PT_SC, ucp_Buginese }, + { 63, PT_SC, ucp_Buhid }, + { 69, PT_GC, ucp_C }, + { 71, PT_SC, ucp_Canadian_Aboriginal }, + { 91, PT_PC, ucp_Cc }, + { 94, PT_PC, ucp_Cf }, + { 97, PT_SC, ucp_Cherokee }, + { 106, PT_PC, ucp_Cn }, + { 109, PT_PC, ucp_Co }, + { 112, PT_SC, ucp_Common }, + { 119, PT_SC, ucp_Coptic }, + { 126, PT_PC, ucp_Cs }, + { 129, PT_SC, ucp_Cuneiform }, + { 139, PT_SC, ucp_Cypriot }, + { 147, PT_SC, ucp_Cyrillic }, + { 156, PT_SC, ucp_Deseret }, + { 164, PT_SC, ucp_Devanagari }, + { 175, PT_SC, ucp_Ethiopic }, + { 184, PT_SC, ucp_Georgian }, + { 193, PT_SC, ucp_Glagolitic }, + { 204, PT_SC, ucp_Gothic }, + { 211, PT_SC, ucp_Greek }, + { 217, PT_SC, ucp_Gujarati }, + { 226, PT_SC, ucp_Gurmukhi }, + { 235, PT_SC, ucp_Han }, + { 239, PT_SC, ucp_Hangul }, + { 246, PT_SC, ucp_Hanunoo }, + { 254, PT_SC, ucp_Hebrew }, + { 261, PT_SC, ucp_Hiragana }, + { 270, PT_SC, ucp_Inherited }, + { 280, PT_SC, ucp_Kannada }, + { 288, PT_SC, ucp_Katakana }, + { 297, PT_SC, ucp_Kharoshthi }, + { 308, PT_SC, ucp_Khmer }, + { 314, PT_GC, ucp_L }, + { 316, PT_LAMP, 0 }, + { 319, PT_SC, ucp_Lao }, + { 323, PT_SC, ucp_Latin }, + { 329, PT_SC, ucp_Limbu }, + { 335, PT_SC, ucp_Linear_B }, + { 344, PT_PC, ucp_Ll }, + { 347, PT_PC, ucp_Lm }, + { 350, PT_PC, ucp_Lo }, + { 353, PT_PC, ucp_Lt }, + { 356, PT_PC, ucp_Lu }, + { 359, PT_GC, ucp_M }, + { 361, PT_SC, ucp_Malayalam }, + { 371, PT_PC, ucp_Mc }, + { 374, PT_PC, ucp_Me }, + { 377, PT_PC, ucp_Mn }, + { 380, PT_SC, ucp_Mongolian }, + { 390, PT_SC, ucp_Myanmar }, + { 398, PT_GC, ucp_N }, + { 400, PT_PC, ucp_Nd }, + { 403, PT_SC, ucp_New_Tai_Lue }, + { 415, PT_SC, ucp_Nko }, + { 419, PT_PC, ucp_Nl }, + { 422, PT_PC, ucp_No }, + { 425, PT_SC, ucp_Ogham }, + { 431, PT_SC, ucp_Old_Italic }, + { 442, PT_SC, ucp_Old_Persian }, + { 454, PT_SC, ucp_Oriya }, + { 460, PT_SC, ucp_Osmanya }, + { 468, PT_GC, ucp_P }, + { 470, PT_PC, ucp_Pc }, + { 473, PT_PC, ucp_Pd }, + { 476, PT_PC, ucp_Pe }, + { 479, PT_PC, ucp_Pf }, + { 482, PT_SC, ucp_Phags_Pa }, + { 491, PT_SC, ucp_Phoenician }, + { 502, PT_PC, ucp_Pi }, + { 505, PT_PC, ucp_Po }, + { 508, PT_PC, ucp_Ps }, + { 511, PT_SC, ucp_Runic }, + { 517, PT_GC, ucp_S }, + { 519, PT_PC, ucp_Sc }, + { 522, PT_SC, ucp_Shavian }, + { 530, PT_SC, ucp_Sinhala }, + { 538, PT_PC, ucp_Sk }, + { 541, PT_PC, ucp_Sm }, + { 544, PT_PC, ucp_So }, + { 547, PT_SC, ucp_Syloti_Nagri }, + { 560, PT_SC, ucp_Syriac }, + { 567, PT_SC, ucp_Tagalog }, + { 575, PT_SC, ucp_Tagbanwa }, + { 584, PT_SC, ucp_Tai_Le }, + { 591, PT_SC, ucp_Tamil }, + { 597, PT_SC, ucp_Telugu }, + { 604, PT_SC, ucp_Thaana }, + { 611, PT_SC, ucp_Thai }, + { 616, PT_SC, ucp_Tibetan }, + { 624, PT_SC, ucp_Tifinagh }, + { 633, PT_SC, ucp_Ugaritic }, + { 642, PT_SC, ucp_Yi }, + { 645, PT_GC, ucp_Z }, + { 647, PT_PC, ucp_Zl }, + { 650, PT_PC, ucp_Zp }, + { 653, PT_PC, ucp_Zs } }; const int _pcre_utt_size = sizeof(_pcre_utt)/sizeof(ucp_type_table); diff --git a/src/src/pcre/pcre_try_flipped.c b/src/src/pcre/pcre_try_flipped.c index 1c08eb6fa..ba97ccb7a 100644 --- a/src/src/pcre/pcre_try_flipped.c +++ b/src/src/pcre/pcre_try_flipped.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_try_flipped.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_try_flipped.c,v 1.6 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -45,6 +45,10 @@ see if it was compiled with the opposite endianness. If so, it uses an auxiliary local function to flip the appropriate bytes. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" @@ -106,6 +110,7 @@ if (byteflip(re->magic_number, sizeof(re->magic_number)) != MAGIC_NUMBER) *internal_re = *re; /* To copy other fields */ internal_re->size = byteflip(re->size, sizeof(re->size)); internal_re->options = byteflip(re->options, sizeof(re->options)); +internal_re->flags = (pcre_uint16)byteflip(re->flags, sizeof(re->flags)); internal_re->top_bracket = (pcre_uint16)byteflip(re->top_bracket, sizeof(re->top_bracket)); internal_re->top_backref = diff --git a/src/src/pcre/pcre_version.c b/src/src/pcre/pcre_version.c index d4f8e2a8a..fa9a7bc9c 100644 --- a/src/src/pcre/pcre_version.c +++ b/src/src/pcre/pcre_version.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcre_version.c,v 1.5 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcre_version.c,v 1.6 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * Perl-Compatible Regular Expressions * @@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE. string that identifies the PCRE version that is in use. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "pcre_internal.h" diff --git a/src/src/pcre/pcretest.c b/src/src/pcre/pcretest.c index 98d10445e..77f6c16db 100644 --- a/src/src/pcre/pcretest.c +++ b/src/src/pcre/pcretest.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/pcre/pcretest.c,v 1.7 2007/06/26 11:16:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/pcre/pcretest.c,v 1.8 2007/11/12 13:02:20 nm4 Exp $ */ /************************************************* * PCRE testing program * @@ -38,6 +38,10 @@ POSSIBILITY OF SUCH DAMAGE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -92,6 +96,7 @@ symbols to prevent clashes. */ #define _pcre_utf8_table4 utf8_table4 #define _pcre_utt utt #define _pcre_utt_size utt_size +#define _pcre_utt_names utt_names #define _pcre_OP_lengths OP_lengths #include "pcre_tables.c" @@ -154,6 +159,7 @@ static int callout_count; static int callout_extra; static int callout_fail_count; static int callout_fail_id; +static int debug_lengths; static int first_callout; static int locale_set = 0; static int show_malloc; @@ -660,6 +666,32 @@ return count; +/************************************************* +* Case-independent strncmp() function * +*************************************************/ + +/* +Arguments: + s first string + t second string + n number of characters to compare + +Returns: < 0, = 0, or > 0, according to the comparison +*/ + +static int +strncmpic(uschar *s, uschar *t, int n) +{ +while (n--) + { + int c = tolower(*s++) - tolower(*t++); + if (c) return c; + } +return 0; +} + + + /************************************************* * Check newline indicator * *************************************************/ @@ -678,11 +710,13 @@ Returns: appropriate PCRE_NEWLINE_xxx flags, or 0 static int check_newline(uschar *p, FILE *f) { -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, "anycrlf>", 8) == 0) return PCRE_NEWLINE_ANYCRLF; -if (strncmp((char *)p, "any>", 4) == 0) return PCRE_NEWLINE_ANY; +if (strncmpic(p, (uschar *)"cr>", 3) == 0) return PCRE_NEWLINE_CR; +if (strncmpic(p, (uschar *)"lf>", 3) == 0) return PCRE_NEWLINE_LF; +if (strncmpic(p, (uschar *)"crlf>", 5) == 0) return PCRE_NEWLINE_CRLF; +if (strncmpic(p, (uschar *)"anycrlf>", 8) == 0) return PCRE_NEWLINE_ANYCRLF; +if (strncmpic(p, (uschar *)"any>", 4) == 0) return PCRE_NEWLINE_ANY; +if (strncmpic(p, (uschar *)"bsr_anycrlf>", 12) == 0) return PCRE_BSR_ANYCRLF; +if (strncmpic(p, (uschar *)"bsr_unicode>", 12) == 0) return PCRE_BSR_UNICODE; fprintf(f, "Unknown newline type at: <%s\n", p); return 0; } @@ -856,6 +890,9 @@ while (argc > 1 && argv[op][0] == '-') (rc == '\n')? "LF" : (rc == ('\r'<<8 | '\n'))? "CRLF" : (rc == -2)? "ANYCRLF" : (rc == -1)? "ANY" : "???"); + (void)pcre_config(PCRE_CONFIG_BSR, &rc); + printf(" \\R matches %s\n", rc? "CR, LF, or CRLF only" : + "all Unicode newlines"); (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc); printf(" Internal link size = %d\n", rc); (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc); @@ -952,7 +989,6 @@ while (!done) size_t size, regex_gotten_store; int do_study = 0; int do_debug = debug; - int debug_lengths = 1; int do_G = 0; int do_g = 0; int do_showinfo = showinfo; @@ -961,6 +997,7 @@ while (!done) int erroroffset, len, delimiter, poffset; use_utf8 = 0; + debug_lengths = 1; if (infile == stdin) printf(" re> "); if (extend_inputline(infile, buffer) == NULL) break; @@ -1317,18 +1354,25 @@ while (!done) if (do_flip) { real_pcre *rre = (real_pcre *)re; - rre->magic_number = byteflip(rre->magic_number, sizeof(rre->magic_number)); + rre->magic_number = + byteflip(rre->magic_number, sizeof(rre->magic_number)); rre->size = byteflip(rre->size, sizeof(rre->size)); rre->options = byteflip(rre->options, sizeof(rre->options)); - rre->top_bracket = byteflip(rre->top_bracket, sizeof(rre->top_bracket)); - rre->top_backref = byteflip(rre->top_backref, sizeof(rre->top_backref)); - rre->first_byte = byteflip(rre->first_byte, sizeof(rre->first_byte)); - rre->req_byte = byteflip(rre->req_byte, sizeof(rre->req_byte)); - rre->name_table_offset = byteflip(rre->name_table_offset, + rre->flags = (pcre_uint16)byteflip(rre->flags, sizeof(rre->flags)); + rre->top_bracket = + (pcre_uint16)byteflip(rre->top_bracket, sizeof(rre->top_bracket)); + rre->top_backref = + (pcre_uint16)byteflip(rre->top_backref, sizeof(rre->top_backref)); + rre->first_byte = + (pcre_uint16)byteflip(rre->first_byte, sizeof(rre->first_byte)); + rre->req_byte = + (pcre_uint16)byteflip(rre->req_byte, sizeof(rre->req_byte)); + rre->name_table_offset = (pcre_uint16)byteflip(rre->name_table_offset, sizeof(rre->name_table_offset)); - rre->name_entry_size = byteflip(rre->name_entry_size, + rre->name_entry_size = (pcre_uint16)byteflip(rre->name_entry_size, sizeof(rre->name_entry_size)); - rre->name_count = byteflip(rre->name_count, sizeof(rre->name_count)); + rre->name_count = (pcre_uint16)byteflip(rre->name_count, + sizeof(rre->name_count)); if (extra != NULL) { @@ -1354,7 +1398,8 @@ while (!done) #if !defined NOINFOCHECK int old_first_char, old_options, old_count; #endif - int count, backrefmax, first_char, need_char, okpartial, jchanged; + int count, backrefmax, first_char, need_char, okpartial, jchanged, + hascrorlf; int nameentrysize, namecount; const uschar *nametable; @@ -1369,6 +1414,7 @@ while (!done) new_info(re, NULL, PCRE_INFO_NAMETABLE, (void *)&nametable); new_info(re, NULL, PCRE_INFO_OKPARTIAL, &okpartial); new_info(re, NULL, PCRE_INFO_JCHANGED, &jchanged); + new_info(re, NULL, PCRE_INFO_HASCRORLF, &hascrorlf); #if !defined NOINFOCHECK old_count = pcre_info(re, &old_options, &old_first_char); @@ -1411,18 +1457,21 @@ while (!done) } if (!okpartial) fprintf(outfile, "Partial matching not supported\n"); + if (hascrorlf) fprintf(outfile, "Contains explicit CR or LF match\n"); all_options = ((real_pcre *)re)->options; if (do_flip) all_options = byteflip(all_options, sizeof(all_options)); if (get_options == 0) fprintf(outfile, "No options\n"); - else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", ((get_options & PCRE_ANCHORED) != 0)? " anchored" : "", ((get_options & PCRE_CASELESS) != 0)? " caseless" : "", ((get_options & PCRE_EXTENDED) != 0)? " extended" : "", ((get_options & PCRE_MULTILINE) != 0)? " multiline" : "", ((get_options & PCRE_FIRSTLINE) != 0)? " firstline" : "", ((get_options & PCRE_DOTALL) != 0)? " dotall" : "", + ((get_options & PCRE_BSR_ANYCRLF) != 0)? " bsr_anycrlf" : "", + ((get_options & PCRE_BSR_UNICODE) != 0)? " bsr_unicode" : "", ((get_options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "", ((get_options & PCRE_EXTRA) != 0)? " extra" : "", ((get_options & PCRE_UNGREEDY) != 0)? " ungreedy" : "", @@ -1555,15 +1604,15 @@ while (!done) else { uschar sbuf[8]; - sbuf[0] = (true_size >> 24) & 255; - sbuf[1] = (true_size >> 16) & 255; - sbuf[2] = (true_size >> 8) & 255; - sbuf[3] = (true_size) & 255; - - sbuf[4] = (true_study_size >> 24) & 255; - sbuf[5] = (true_study_size >> 16) & 255; - sbuf[6] = (true_study_size >> 8) & 255; - sbuf[7] = (true_study_size) & 255; + sbuf[0] = (uschar)((true_size >> 24) & 255); + sbuf[1] = (uschar)((true_size >> 16) & 255); + sbuf[2] = (uschar)((true_size >> 8) & 255); + sbuf[3] = (uschar)((true_size) & 255); + + sbuf[4] = (uschar)((true_study_size >> 24) & 255); + sbuf[5] = (uschar)((true_study_size >> 16) & 255); + sbuf[6] = (uschar)((true_study_size >> 8) & 255); + sbuf[7] = (uschar)((true_study_size) & 255); if (fwrite(sbuf, 1, 8, f) < 8 || fwrite(re, 1, true_size, f) < true_size) -- 2.25.1