diff options
author | nigel <nigel@2f5784b3-3f2a-0410-8824-cb99058d5e15> | 2007-02-24 21:38:13 +0000 |
---|---|---|
committer | nigel <nigel@2f5784b3-3f2a-0410-8824-cb99058d5e15> | 2007-02-24 21:38:13 +0000 |
commit | 91453b91d322e9d5812026584c2ecbe8f4cab52a (patch) | |
tree | b87e19c06fa0a5304d6b611bb5999b4fadaac77d | |
parent | 94ffc03e8ac1628911f231a91d7d8d94c2f0dc38 (diff) | |
download | pcre-91453b91d322e9d5812026584c2ecbe8f4cab52a.tar.gz |
Load pcre-1.03 into code/trunk.
git-svn-id: svn://vcs.exim.org/pcre/code/trunk@9 2f5784b3-3f2a-0410-8824-cb99058d5e15
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | internal.h | 10 | ||||
-rw-r--r-- | pcre.3 | 2 | ||||
-rw-r--r-- | pcre.c | 240 | ||||
-rw-r--r-- | pcre.h | 1 | ||||
-rw-r--r-- | pcretest.c | 17 | ||||
-rw-r--r-- | testinput | 45 | ||||
-rw-r--r-- | testinput2 | 4 | ||||
-rw-r--r-- | testoutput | 68 | ||||
-rw-r--r-- | testoutput2 | 8 |
11 files changed, 306 insertions, 137 deletions
@@ -2,6 +2,52 @@ ChangeLog for PCRE ------------------ +Version 1.03 18-Dec-97 +---------------------- + +1. A erroneous regex with a missing opening parenthesis was correctly +diagnosed, but PCRE attempted to access brastack[-1], which could cause crashes +on some systems. + +2. Replaced offsetof(real_pcre, code) by offsetof(real_pcre, code[0]) because +it was reported that one broken compiler failed on the former because "code" is +also an independent variable. + +3. The erroneous regex a[]b caused an array overrun reference. + +4. A regex ending with a one-character negative class (e.g. /[^k]$/) did not +fail on data ending with that character. (It was going on too far, and checking +the next character, typically a binary zero.) This was specific to the +optimized code for single-character negative classes. + +5. Added a contributed patch from the TIN world which does the following: + + + Add an undef for memmove, in case the the system defines a macro for it. + + + Add a definition of offsetof(), in case there isn't one. (I don't know + the reason behind this - offsetof() is part of the ANSI standard - but + it does no harm). + + + Reduce the ifdef's in pcre.c using macro DPRINTF, thereby eliminating + most of the places where whitespace preceded '#'. I have given up and + allowed the remaining 2 cases to be at the margin. + + + Rename some variables in pcre to eliminate shadowing. This seems very + pedantic, but does no harm, of course. + +6. Moved the call to setjmp() into its own function, to get rid of warnings +from gcc -Wall, and avoided calling it at all unless PCRE_EXTRA is used. + +7. Constructs such as \d{8,} were compiling into the equivalent of +\d{8}\d{65527} instead of \d{8}\d* which didn't make much difference to the +outcome, but in this particular case used more store than had been allocated, +which caused the bug to be discovered because it threw up an internal error. + +8. The debugging code in both pcre and pcretest for outputting the compiled +form of a regex was going wrong in the case of back references followed by +curly-bracketed repeats. + + Version 1.02 12-Dec-97 ---------------------- @@ -12,7 +12,7 @@ # lacks the strerror() function, but can provide the equivalent by indexing # into errlist. -CC = gcc -O2 +CC = gcc -O2 -Wall CFLAGS = RANLIB = @true @@ -3,7 +3,7 @@ *************************************************/ -#define PCRE_VERSION "1.02 12-Dec-1997" +#define PCRE_VERSION "1.03 18-Dec-1997" /* This is a library of functions to support regular expressions whose syntax @@ -38,6 +38,7 @@ modules, but which are not relevant to the outside. */ define a macro for memmove() if USE_BCOPY is defined. */ #ifdef USE_BCOPY +#undef memmove /* some systems may have a macro */ #define memmove(a, b, c) bcopy(b, a, c) #endif @@ -52,6 +53,13 @@ define a macro for memmove() if USE_BCOPY is defined. */ #include <string.h> #include "pcre.h" +/* In case there is no definition of offsetof() provided - though any proper +Standard C system should have one. */ + +#ifndef offsetof +#define offsetof(p_type,field) ((size_t)&(((p_type)0)->field)) +#endif + /* Private options flags start at the most significant end of the two bytes. The public options defined in pcre.h start at the least significant end. Make sure they don't overlap! */ @@ -603,7 +603,7 @@ operation from backtracking past it. For example, if the expression .*/foo -is matched against the string "/foo/this/is/not" then after the greedy .* +is matched against the string "/this/string/is/not" then after the greedy .* has swallowed the whole string, PCRE keeps backtracking all the way to the beginning before failing. If, on the other hand, the expression is @@ -33,6 +33,15 @@ restrictions: /* #define DEBUG */ +/* Use a macro for debugging printing, 'cause that eliminates the the use +of #ifdef inline, and there are *still* stupid compilers about that don't like +indented pre-processor statements. I suppose it's only been 10 years... */ + +#ifdef DEBUG +#define DPRINTF(p) printf p +#else +#define DPRINTF(p) /*nothing*/ +#endif /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ @@ -187,7 +196,8 @@ Arguments: Returns: nothing */ -static pchars(uschar *p, int length, BOOL is_subject, match_data *md) +static void +pchars(const uschar *p, int length, BOOL is_subject, match_data *md) { int c; if (is_subject && length > md->end_subject - p) length = md->end_subject - p; @@ -977,9 +987,17 @@ for (;; ptr++) if (code == previous) code += 2; else previous[1]++; } - /* Insert an UPTO if the max is greater than the min. */ + /* If the maximum is unlimited, insert an OP_STAR. */ + + if (repeat_max < 0) + { + *code++ = c; + *code++ = OP_STAR + repeat_type; + } + + /* Else insert an UPTO if the max is greater than the min. */ - if (repeat_max != repeat_min) + else if (repeat_max != repeat_min) { *code++ = c; repeat_max -= repeat_min; @@ -1023,7 +1041,7 @@ for (;; ptr++) else if ((int)*previous >= OP_BRA) { int i; - int length = code - previous; + int len = code - previous; if (repeat_max == -1 && could_be_empty(previous)) { @@ -1040,8 +1058,8 @@ for (;; ptr++) { for (i = 1; i < repeat_min; i++) { - memcpy(code, previous, length); - code += length; + memcpy(code, previous, len); + code += len; } } @@ -1053,22 +1071,22 @@ for (;; ptr++) { if (repeat_min == 0) { - memmove(previous+1, previous, length); + memmove(previous+1, previous, len); code++; *previous++ = OP_BRAZERO + repeat_type; } for (i = 1; i < repeat_min; i++) { - memcpy(code, previous, length); - code += length; + memcpy(code, previous, len); + code += len; } for (i = (repeat_min > 0)? repeat_min : 1; i < repeat_max; i++) { *code++ = OP_BRAZERO + repeat_type; - memcpy(code, previous, length); - code += length; + memcpy(code, previous, len); + code += len; } } @@ -1529,10 +1547,8 @@ if ((options & ~PUBLIC_OPTIONS) != 0) return NULL; } -#ifdef DEBUG -printf("------------------------------------------------------------------\n"); -printf("%s\n", pattern); -#endif +DPRINTF(("------------------------------------------------------------------\n")); +DPRINTF(("%s\n", pattern)); /* The first thing to do is to make a pass over the pattern to compute the amount of store required to hold the compiled code. This does not have to be @@ -1647,9 +1663,9 @@ while ((c = *(++ptr)) != 0) { if (*ptr == '\\') { - int c = check_escape(&ptr, errorptr, bracount, options, TRUE); + int ch = check_escape(&ptr, errorptr, bracount, options, TRUE); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if (-c == ESC_b) class_charcount++; else class_charcount = 10; + if (-ch == ESC_b) class_charcount++; else class_charcount = 10; } else class_charcount++; ptr++; @@ -1664,7 +1680,7 @@ while ((c = *(++ptr)) != 0) /* A repeat needs either 1 or 5 bytes. */ - if (ptr[1] == '{' && is_counted_repeat(ptr+2)) + if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; @@ -1772,37 +1788,38 @@ while ((c = *(++ptr)) != 0) continue; /* Handle ket. Look for subsequent max/min; for certain sets of values we - have to replicate this bracket up to that many times. */ + have to replicate this bracket up to that many times. If brastackptr is + 0 this is an unmatched bracket which will generate an error, but take care + not to try to access brastack[-1]. */ case ')': length += 3; { - int min = 1; - int max = 1; - int duplength = length - brastack[--brastackptr]; + int minval = 1; + int maxval = 1; + int duplength = (brastackptr > 0)? length - brastack[--brastackptr] : 0; /* Leave ptr at the final char; for read_repeat_counts this happens automatically; for the others we need an increment. */ if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2)) { - ptr = read_repeat_counts(ptr+2, &min, &max, errorptr); + ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; } - else if (c == '*') { min = 0; max = -1; ptr++; } - else if (c == '+') { max = -1; ptr++; } - else if (c == '?') { min = 0; ptr++; } + else if (c == '*') { minval = 0; maxval = -1; ptr++; } + else if (c == '+') { maxval = -1; ptr++; } + else if (c == '?') { minval = 0; ptr++; } - /* If there is a minimum > 1 we have to replicate up to min-1 times; if - there is a limited maximum we have to replicate up to max-1 times and - allow for a BRAZERO item before each optional copy, as we also have to - do before the first copy if the minimum is zero. */ + /* If there is a minimum > 1 we have to replicate up to minval-1 times; + if there is a limited maximum we have to replicate up to maxval-1 times + and allow for a BRAZERO item before each optional copy, as we also have + to do before the first copy if the minimum is zero. */ - if (min == 0) length++; - else if (min > 1) length += (min - 1) * duplength; - if (max > min) length += (max - min) * (duplength + 1); + if (minval == 0) length++; + else if (minval > 1) length += (minval - 1) * duplength; + if (maxval > minval) length += (maxval - minval) * (duplength + 1); } - continue; /* Non-special character. For a run of such characters the length required @@ -1863,9 +1880,12 @@ if (length > 65539) } /* Compute the size of data block needed and get it, either from malloc or -externally provided function. Put in the magic number and the options. */ +externally provided function. We specify "code[0]" in the offsetof() expression +rather than just "code", because it has been reported that one broken compiler +fails on "code" because it is also an independent variable. It should make no +difference to the value of the offsetof(). */ -size = length + offsetof(real_pcre, code); +size = length + offsetof(real_pcre, code[0]); re = (real_pcre *)(pcre_malloc)(size); if (re == NULL) @@ -1874,6 +1894,8 @@ if (re == NULL) return NULL; } +/* Put in the magic number and the options. */ + re->magic_number = MAGIC_NUMBER; re->options = options; @@ -1924,10 +1946,10 @@ if ((options & PCRE_ANCHORED) == 0) re->options |= PCRE_ANCHORED; else { - int c = find_firstchar(re->code); - if (c >= 0) + int ch = find_firstchar(re->code); + if (ch >= 0) { - re->first_char = c; + re->first_char = ch; re->options |= PCRE_FIRSTSET; } else if (is_startline(re->code)) @@ -2064,7 +2086,8 @@ while (code < code_end) case OP_REF: printf(" \\%d", *(++code)); - break; + code ++; + goto CLASS_REF_REPEAT; case OP_CLASS: { @@ -2094,6 +2117,8 @@ while (code < code_end) printf("]"); code += 32; + CLASS_REF_REPEAT: + switch(*code) { case OP_CRSTAR: @@ -2278,9 +2303,7 @@ for (;;) int number = (*ecode - OP_BRA) << 1; int save_offset1 = 0, save_offset2 = 0; - #ifdef DEBUG - printf("start bracket %d\n", number/2); - #endif + DPRINTF(("start bracket %d\n", number/2)); if (number > 0 && number < md->offset_end) { @@ -2288,9 +2311,7 @@ for (;;) save_offset2 = md->offset_vector[number+1]; md->offset_vector[number] = eptr - md->start_subject; - #ifdef DEBUG - printf("saving %d %d\n", save_offset1, save_offset2); - #endif + DPRINTF(("saving %d %d\n", save_offset1, save_offset2)); } /* Recurse for all the alternatives. */ @@ -2302,9 +2323,7 @@ for (;;) } while (*ecode == OP_ALT); - #ifdef DEBUG - printf("bracket %d failed\n", number/2); - #endif + DPRINTF(("bracket %d failed\n", number/2)); if (number > 0 && number < md->offset_end) { @@ -2443,9 +2462,7 @@ for (;;) number = (*prev - OP_BRA) << 1; - #ifdef DEBUG - printf("end bracket %d\n", number/2); - #endif + DPRINTF(("end bracket %d\n", number/2)); if (number > 0) { @@ -2813,7 +2830,7 @@ for (;;) register int length = ecode[1]; ecode += 2; - #ifdef DEBUG +#ifdef DEBUG /* Sigh. Some compilers never learn. */ if (eptr >= md->end_subject) printf("matching subject <null> against pattern "); else @@ -2824,7 +2841,7 @@ for (;;) } pchars(ecode, length, FALSE, md); printf("\n"); - #endif +#endif if (length > md->end_subject - eptr) return FALSE; if (md->caseless) @@ -2881,10 +2898,8 @@ for (;;) maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ - #ifdef DEBUG - printf("matching %c{%d,%d} against subject %.*s\n", c, min, max, - max, eptr); - #endif + DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max, + max, eptr)); if (md->caseless) { @@ -2949,7 +2964,7 @@ for (;;) /* Match a negated single character */ case OP_NOT: - if (eptr > md->end_subject) return FALSE; + if (eptr >= md->end_subject) return FALSE; ecode++; if (md->caseless) { @@ -3008,10 +3023,8 @@ for (;;) maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ - #ifdef DEBUG - printf("negative matching %c{%d,%d} against subject %.*s\n", c, min, max, - max, eptr); - #endif + DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max, + max, eptr)); if (md->caseless) { @@ -3261,9 +3274,7 @@ for (;;) /* There's been some horrible disaster. */ default: - #ifdef DEBUG - printf("Unknown opcode %d\n", *ecode); - #endif + DPRINTF(("Unknown opcode %d\n", *ecode)); md->errorcode = PCRE_ERROR_UNKNOWN_NODE; return FALSE; } @@ -3279,6 +3290,28 @@ for (;;) /************************************************* +* Segregate setjmp() * +*************************************************/ + +/* The -Wall option of gcc gives warnings for all local variables when setjmp() +is used, even if the coding conforms to the rules of ANSI C. To avoid this, we +hide it in a separate function. This is called only when PCRE_EXTRA is set, +since it's needed only for the extension \X option, and with any luck, a good +compiler will spot the tail recursion and compile it efficiently. + +Arguments: The block containing the match data +Returns: The return from setjump() +*/ + +static int +my_setjmp(match_data *match_block) +{ +return setjmp(match_block->fail_env); +} + + + +/************************************************* * Execute a Regular Expression * *************************************************/ @@ -3310,7 +3343,7 @@ int ocount = offsetcount; int first_char = -1; match_data match_block; const uschar *start_bits = NULL; -const uschar *start_match = (uschar *)subject; +const uschar *start_match = (const uschar *)subject; const uschar *end_subject; const real_pcre *re = (const real_pcre *)external_re; const real_pcre_extra *extra = (const real_pcre_extra *)external_extra; @@ -3351,9 +3384,7 @@ if (re->top_backref > 0 && re->top_backref + 1 >= ocount/2) ocount = re->top_backref * 2 + 2; match_block.offset_vector = (pcre_malloc)(ocount * sizeof(int)); if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; - #ifdef DEBUG - printf("Got memory to hold back references\n"); - #endif + DPRINTF(("Got memory to hold back references\n")); } else match_block.offset_vector = offsets; @@ -3406,6 +3437,7 @@ if (!anchored) do { + int rc; register int *iptr = match_block.offset_vector; register int *iend = iptr + resetcount; @@ -3447,11 +3479,11 @@ do } } - #ifdef DEBUG +#ifdef DEBUG /* Sigh. Some compilers never learn. */ printf(">>>> Match against: "); pchars(start_match, end_subject - start_match, TRUE, &match_block); printf("\n"); - #endif +#endif /* When a match occurs, substrings will be set for all internal extractions; we just need to set up the whole thing as substring 0 before returning. If @@ -3461,54 +3493,48 @@ do if certain parts of the pattern were not used. Before starting the match, we have to set up a longjmp() target to enable - the "cut" operation to fail a match completely without backtracking. */ - - if (setjmp(match_block.fail_env) == 0 && - match(start_match, re->code, 2, &match_block)) - { - int rc; + the "cut" operation to fail a match completely without backtracking. This + is done in a separate function to avoid compiler warnings. We need not do + it unless PCRE_EXTRA is set, since only in that case is the "cut" operation + enabled. */ - if (ocount != offsetcount) - { - if (offsetcount >= 4) - { - memcpy(offsets + 2, match_block.offset_vector + 2, - (offsetcount - 2) * sizeof(int)); - #ifdef DEBUG - printf("Copied offsets; freeing temporary memory\n"); - #endif - } - if (match_block.end_offset_top > offsetcount) - match_block.offset_overflow = TRUE; + if (((re->options & PCRE_EXTRA) != 0 && my_setjmp(&match_block) != 0) || + !match(start_match, re->code, 2, &match_block)) + continue; - #ifdef DEBUG - printf("Freeing temporary memory\n"); - #endif + /* Copy the offset information from temporary store if necessary */ - (pcre_free)(match_block.offset_vector); + if (ocount != offsetcount) + { + if (offsetcount >= 4) + { + memcpy(offsets + 2, match_block.offset_vector + 2, + (offsetcount - 2) * sizeof(int)); + DPRINTF(("Copied offsets; freeing temporary memory\n")); } + if (match_block.end_offset_top > offsetcount) + match_block.offset_overflow = TRUE; - rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; + DPRINTF(("Freeing temporary memory\n")); + (pcre_free)(match_block.offset_vector); + } - if (match_block.offset_end < 2) rc = 0; else - { - offsets[0] = start_match - match_block.start_subject; - offsets[1] = match_block.end_match_ptr - match_block.start_subject; - } + rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; - #ifdef DEBUG - printf(">>>> returning %d\n", rc); - #endif - return rc; + if (match_block.offset_end < 2) rc = 0; else + { + offsets[0] = start_match - match_block.start_subject; + offsets[1] = match_block.end_match_ptr - match_block.start_subject; } + + DPRINTF((">>>> returning %d\n", rc)); + return rc; } while (!anchored && match_block.errorcode == PCRE_ERROR_NOMATCH && start_match++ < end_subject); -#ifdef DEBUG -printf(">>>> returning %d\n", match_block.errorcode); -#endif +DPRINTF((">>>> returning %d\n", match_block.errorcode)); return match_block.errorcode; } @@ -10,6 +10,7 @@ /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ +#include <sys/types.h> #include <stdlib.h> /* Options */ @@ -157,7 +157,8 @@ for(;;) case OP_REF: printf(" \\%d", *(++code)); - break; + code++; + goto CLASS_REF_REPEAT; case OP_CLASS: { @@ -187,6 +188,8 @@ for(;;) printf("]"); code += 32; + CLASS_REF_REPEAT: + switch(*code) { case OP_CRSTAR: @@ -581,7 +584,7 @@ for (;;) for (;;) { - unsigned char *pp; + unsigned char *q; int count, c; int offsets[30]; int size_offsets = sizeof(offsets)/sizeof(int); @@ -600,7 +603,7 @@ for (;;) p = buffer; while (isspace(*p)) p++; - pp = dbuffer; + q = dbuffer; while ((c = *p++) != 0) { int i = 0; @@ -662,17 +665,17 @@ for (;;) case 'O': while(isdigit(*p)) n = n * 10 + *p++ - '0'; - if (n <= (int)sizeof(offsets)/sizeof(int)) size_offsets = n; + if (n <= (int)(sizeof(offsets)/sizeof(int))) size_offsets = n; continue; case 'Z': options |= PCRE_NOTEOL; continue; } - *pp++ = c; + *q++ = c; } - *pp = 0; - len = pp - dbuffer; + *q = 0; + len = q - dbuffer; /* Handle matching via the POSIX interface, which does not support timing. */ @@ -1489,12 +1489,12 @@ abc\100\60 /abc\81/ - abc\081 - abc\0\x38\x31 + abc\081 + abc\0\x38\x31 /abc\91/ - abc\091 - abc\0\x39\x31 + abc\091 + abc\0\x39\x31 /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/ abcdefghijkllS @@ -1534,18 +1534,45 @@ baccd /[^a]/ - Abc + Abc /[^a]/i - Abc + Abc /[^a]+/ - AAAaAbc + AAAaAbc /[^a]+/i - AAAaAbc + AAAaAbc /[^a]+/ - bbb\nccc + bbb\nccc + +/[^k]$/ + abc + *** Failers + abk + +/[^k]{2,3}$/ + abc + kbc + kabc + *** Failers + abk + akb + akk + +/^\d{8,}\@.+[^k]$/ + 12345678\@a.b.c.d + 123456789\@x.y.z + *** Failers + 12345678\@x.y.uk + 1234567\@a.b.c.d + +/(a)\1{8,}/ + aaaaaaaaa + aaaaaaaaaa + *** Failers + aaaaaaa / End of test input / @@ -263,4 +263,8 @@ /((?>a*?))*/X +/)/ + +/a[]b/ + / End of test input / @@ -1,5 +1,5 @@ Testing Perl-Compatible Regular Expressions -PCRE version 1.02 12-Dec-1997 +PCRE version 1.03 18-Dec-1997 /the quick brown fox/ the quick brown fox @@ -2165,15 +2165,15 @@ No match 1: abc /abc\81/ - abc\081 + abc\081 0: abc\x0081 - abc\0\x38\x31 + abc\0\x38\x31 0: abc\x0081 /abc\91/ - abc\091 + abc\091 0: abc\x0091 - abc\0\x39\x31 + abc\0\x39\x31 0: abc\x0091 /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/ @@ -2275,24 +2275,72 @@ No match No match /[^a]/ - Abc + Abc 0: A /[^a]/i - Abc + Abc 0: b /[^a]+/ - AAAaAbc + AAAaAbc 0: AAA /[^a]+/i - AAAaAbc + AAAaAbc 0: bc /[^a]+/ - bbb\nccc + bbb\nccc 0: bbb\x0accc + +/[^k]$/ + abc + 0: c + *** Failers + 0: s + abk +No match + +/[^k]{2,3}$/ + abc + 0: abc + kbc + 0: bc + kabc + 0: abc + *** Failers + 0: ers + abk +No match + akb +No match + akk +No match + +/^\d{8,}\@.+[^k]$/ + 12345678\@a.b.c.d + 0: 12345678@a.b.c.d + 123456789\@x.y.z + 0: 123456789@x.y.z + *** Failers +No match + 12345678\@x.y.uk +No match + 1234567\@a.b.c.d +No match + +/(a)\1{8,}/ + aaaaaaaaa + 0: aaaaaaaaa + 1: a + aaaaaaaaaa + 0: aaaaaaaaaa + 1: a + *** Failers +No match + aaaaaaa +No match / End of test input / diff --git a/testoutput2 b/testoutput2 index 4034a2e..23da939 100644 --- a/testoutput2 +++ b/testoutput2 @@ -1,5 +1,5 @@ Testing Perl-Compatible Regular Expressions -PCRE version 1.02 12-Dec-1997 +PCRE version 1.03 18-Dec-1997 /(a)b|/ Identifying subpattern count = 1 @@ -599,6 +599,12 @@ Failed: operand of unlimited repeat could match the empty string at offset 8 /((?>a*?))*/X Failed: operand of unlimited repeat could match the empty string at offset 9 +/)/ +Failed: unmatched brackets at offset 0 + +/a[]b/ +Failed: missing terminating ] for character class at offset 4 + / End of test input / Identifying subpattern count = 0 No options |