Index: ossp-pkg/str/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/str/.cvsignore,v rcsdiff -q -kk '-r1.10' '-r1.11' -u '/v/ossp/cvs/ossp-pkg/str/.cvsignore,v' 2>/dev/null --- .cvsignore 2001/09/10 09:55:13 1.10 +++ .cvsignore 2001/12/27 12:24:20 1.11 @@ -22,3 +22,4 @@ str.3 str-config.1 str.h +str_pcre.tab Index: ossp-pkg/str/Makefile.in RCS File: /v/ossp/cvs/ossp-pkg/str/Makefile.in,v rcsdiff -q -kk '-r1.38' '-r1.39' -u '/v/ossp/cvs/ossp-pkg/str/Makefile.in,v' 2>/dev/null --- Makefile.in 2001/12/27 12:16:44 1.38 +++ Makefile.in 2001/12/27 12:24:20 1.39 @@ -113,12 +113,12 @@ NAME="Str"; ONELINE="String Library"; \ $(_MANPAGE) -str_pcre.lo: str_pcre.c -str_pcre.c: str_pcre_tab.c -str_pcre_tab.c: str_pcre_gen - ./str_pcre_gen >str_pcre_tab.c -str_pcre_gen: - $(CC) $(CFLAGS) -DSTR_PCRE_GENTAB $(LDFLAGS) -o str_pcre_gen str_pcre.c $(LIBS) + +str_pcre.lo: str_pcre.tab str_pcre.c +str_pcre.tab: str_pcre.c + $(CC) $(CFLAGS) -DSTR_PCRE_TAB $(LDFLAGS) -o str_pcre.gen str_pcre.c $(LIBS) + ./str_pcre.gen >str_pcre.tab + -rm -f str_pcre.gen check: test test: str_test @@ -139,14 +139,13 @@ clean: $(RM) *.lo *.o $(RM) str_test.o str_test - $(RM) str_pcre_gen str_pcre_tab.c $(RM) libstr.la $(RM) -r .libs distclean: clean $(RM) str-config $(RM) str_config.h - $(RM) str_pcre_mk str_pcre_tab.c + $(RM) str_pcre.tab $(RM) config.log config.cache config.status $(RM) libtool $(RM) Makefile Index: ossp-pkg/str/str_pcre.c RCS File: /v/ossp/cvs/ossp-pkg/str/str_pcre.c,v rcsdiff -q -kk '-r1.5' '-r1.6' -u '/v/ossp/cvs/ossp-pkg/str/str_pcre.c,v' 2>/dev/null --- str_pcre.c 2001/08/16 12:04:25 1.5 +++ str_pcre.c 2001/12/27 12:24:20 1.6 @@ -1,50 +1,50 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ +/* + * Perl Compatible Regular Expression (PCRE) Library + * Copyright (c) 1997-2001 Philip Hazel + * Copyright (c) 1997-2001 University of Cambridge + * + * DO NOT EDIT THIS FILE, IT WAS AUTOMATICALLY GENERATED! + * + * This is an automatically generated, extremely stripped down + * version of the PCRE 3.8 library from the Philip Hazel. + * This version is still distributed under the same original PCRE + * Open Source license, but Philip Hazel is no longer responsible + * for this version. + */ + +/* + This is a library of functions to support regular expressions whose syntax + and semantics are as close as possible to those of the Perl 5 language. See + the file Tech.Notes for some information on the internals. + + Written by: Philip Hazel + + Copyright (c) 1997-2001 University of Cambridge + + ----------------------------------------------------------------------------- + Permission is granted to anyone to use this software for any purpose on any + computer system, and to redistribute it freely, subject to the following + restrictions: + + 1. This software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. -/* -This is a library of functions to support regular expressions whose syntax -and semantics are as close as possible to those of the Perl 5 language. See -the file Tech.Notes for some information on the internals. + 2. The origin of this software must not be misrepresented, either by explicit + claim or by omission. -Written by: Philip Hazel - - Copyright (c) 1997-2001 University of Cambridge - ------------------------------------------------------------------------------ -Permission is granted to anyone to use this software for any purpose on any -computer system, and to redistribute it freely, subject to the following -restrictions: - -1. This software is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -2. The origin of this software must not be misrepresented, either by - explicit claim or by omission. - -3. Altered versions must be plainly marked as such, and must not be + 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. -4. If PCRE is embedded in any software that is released under the GNU - General Purpose Licence (GPL), then the terms of that licence shall - supersede any condition above with which it is incompatible. ------------------------------------------------------------------------------ -*/ - -/* ____ BEGIN internal.h ____ */ - -/* This header contains definitions that are shared between the different -modules, but which are not relevant to the outside. */ - -/* Get the definitions provided by running "configure" */ + 4. If PCRE is embedded in any software that is released under the GNU General + Purpose Licence (GPL), then the terms of that licence shall supersede any + condition above with which it is incompatible. + ----------------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -/* Standard C headers plus the external interface definition */ - #include #include #include @@ -53,35 +53,19 @@ #include #include "str_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 -/* These are the public options that can change during matching. */ - #define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) -/* Private options flags start at the most significant end of the four bytes, -but skip the top bit so we can use ints for convenience without getting tangled -with negative values. The public options defined in pcre.h start at the least -significant end. Make sure they don't overlap, though now that we have expanded -to four bytes there is plenty of space. */ - -#define PCRE_FIRSTSET 0x40000000 /* first_char is set */ -#define PCRE_REQCHSET 0x20000000 /* req_char is set */ -#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ -#define PCRE_INGROUP 0x08000000 /* compiling inside a group */ -#define PCRE_ICHANGED 0x04000000 /* i option changes within regex */ - -/* Options for the "extra" block produced by pcre_study(). */ +#define PCRE_FIRSTSET 0x40000000 +#define PCRE_REQCHSET 0x20000000 +#define PCRE_STARTLINE 0x10000000 +#define PCRE_INGROUP 0x08000000 +#define PCRE_ICHANGED 0x04000000 -#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ - -/* Masks for identifying the public options which are permitted at compile -time, run time or study time, respectively. */ +#define PCRE_STUDY_MAPPED 0x01 #define PUBLIC_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ @@ -90,13 +74,9 @@ #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY) -#define PUBLIC_STUDY_OPTIONS 0 /* None defined */ - -/* Magic number to provide a small check against being handed junk. */ +#define PUBLIC_STUDY_OPTIONS 0 -#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ - -/* Miscellaneous definitions */ +#define MAGIC_NUMBER 0x50435245UL typedef int BOOL; @@ -107,10 +87,6 @@ #define TRUE 1 #endif -/* Escape items that are just an encoding of a particular data value. Note that -ESC_N is defined as yet another macro, which is set in config.h to either \n -(the default) or \r (which some people want). */ - #ifndef ESC_E #define ESC_E 27 #endif @@ -131,132 +107,99 @@ #define ESC_T '\t' #endif -/* These are escaped items that aren't just an encoding of a particular data -value such as \n. They must have non-zero values, as check_escape() returns -their negation. Also, they must appear in the same order as in the opcode -definitions below, up to ESC_z. The final one must be ESC_REF as subsequent -values are used for \1, \2, \3, etc. There is a test in the code for an escape -greater than ESC_b and less than ESC_Z to detect the types that may be -repeated. If any new escapes are put in-between that don't consume a character, -that code will have to change. */ - enum { ESC_A = 1, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, - ESC_Z, ESC_z, ESC_REF }; - -/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets -that extract substrings. Starting from 1 (i.e. after OP_END), the values up to -OP_EOD must correspond in order to the list of escapes immediately above. */ + ESC_Z, ESC_z, ESC_REF +}; enum { - OP_END, + OP_END, - /* Values corresponding to backslashed metacharacters */ + OP_SOD, + OP_NOT_WORD_BOUNDARY, + OP_WORD_BOUNDARY, + OP_NOT_DIGIT, + OP_DIGIT, + OP_NOT_WHITESPACE, + OP_WHITESPACE, + OP_NOT_WORDCHAR, + OP_WORDCHAR, + OP_EODN, + OP_EOD, + + OP_OPT, + OP_CIRC, + OP_DOLL, + OP_ANY, + OP_CHARS, + OP_NOT, + + OP_STAR, + OP_MINSTAR, + OP_PLUS, + OP_MINPLUS, + OP_QUERY, + OP_MINQUERY, + OP_UPTO, + OP_MINUPTO, + OP_EXACT, + + OP_NOTSTAR, + OP_NOTMINSTAR, + OP_NOTPLUS, + OP_NOTMINPLUS, + OP_NOTQUERY, + OP_NOTMINQUERY, + OP_NOTUPTO, + OP_NOTMINUPTO, + OP_NOTEXACT, + + OP_TYPESTAR, + OP_TYPEMINSTAR, + OP_TYPEPLUS, + OP_TYPEMINPLUS, + OP_TYPEQUERY, + OP_TYPEMINQUERY, + OP_TYPEUPTO, + OP_TYPEMINUPTO, + OP_TYPEEXACT, + + OP_CRSTAR, + OP_CRMINSTAR, + OP_CRPLUS, + OP_CRMINPLUS, + OP_CRQUERY, + OP_CRMINQUERY, + OP_CRRANGE, + OP_CRMINRANGE, + + OP_CLASS, + OP_REF, + OP_RECURSE, + + OP_ALT, + OP_KET, + OP_KETRMAX, + OP_KETRMIN, + + OP_ASSERT, + OP_ASSERT_NOT, + OP_ASSERTBACK, + OP_ASSERTBACK_NOT, + OP_REVERSE, + + OP_ONCE, + OP_COND, + OP_CREF, - OP_SOD, /* Start of data: \A */ - OP_NOT_WORD_BOUNDARY, /* \B */ - OP_WORD_BOUNDARY, /* \b */ - OP_NOT_DIGIT, /* \D */ - OP_DIGIT, /* \d */ - OP_NOT_WHITESPACE, /* \S */ - OP_WHITESPACE, /* \s */ - OP_NOT_WORDCHAR, /* \W */ - OP_WORDCHAR, /* \w */ - OP_EODN, - OP_EOD, - - OP_OPT, /* Set runtime options */ - OP_CIRC, /* Start of line - varies with multiline switch */ - OP_DOLL, - OP_ANY, /* Match any character */ - OP_CHARS, /* Match string of characters */ - OP_NOT, /* Match anything but the following char */ - - OP_STAR, /* The maximizing and minimizing versions of */ - OP_MINSTAR, /* all these opcodes must come in pairs, with */ - OP_PLUS, /* the minimizing one second. */ - OP_MINPLUS, /* This first set applies to single characters */ - OP_QUERY, - OP_MINQUERY, - OP_UPTO, /* From 0 to n matches */ - OP_MINUPTO, - OP_EXACT, /* Exactly n matches */ - - OP_NOTSTAR, /* The maximizing and minimizing versions of */ - OP_NOTMINSTAR, /* all these opcodes must come in pairs, with */ - OP_NOTPLUS, /* the minimizing one second. */ - OP_NOTMINPLUS, /* This first set applies to "not" single characters */ - OP_NOTQUERY, - OP_NOTMINQUERY, - OP_NOTUPTO, /* From 0 to n matches */ - OP_NOTMINUPTO, - OP_NOTEXACT, /* Exactly n matches */ - - OP_TYPESTAR, /* The maximizing and minimizing versions of */ - OP_TYPEMINSTAR, /* all these opcodes must come in pairs, with */ - OP_TYPEPLUS, /* the minimizing one second. These codes must */ - OP_TYPEMINPLUS, /* be in exactly the same order as those above. */ - OP_TYPEQUERY, /* This set applies to character types such as \d */ - OP_TYPEMINQUERY, - OP_TYPEUPTO, /* From 0 to n matches */ - OP_TYPEMINUPTO, - OP_TYPEEXACT, /* Exactly n matches */ - - OP_CRSTAR, /* The maximizing and minimizing versions of */ - OP_CRMINSTAR, /* all these opcodes must come in pairs, with */ - OP_CRPLUS, /* the minimizing one second. These codes must */ - OP_CRMINPLUS, /* be in exactly the same order as those above. */ - OP_CRQUERY, /* These are for character classes and back refs */ - OP_CRMINQUERY, - OP_CRRANGE, /* These are different to the three seta above. */ - OP_CRMINRANGE, - - OP_CLASS, /* Match a character class */ - OP_REF, /* Match a back reference */ - OP_RECURSE, /* Match this pattern recursively */ - - OP_ALT, /* Start of alternation */ - OP_KET, - OP_KETRMAX, /* These two must remain together and in this */ - OP_KETRMIN, /* order. They are for groups the repeat for ever. */ - - /* The assertions must come before ONCE and COND */ - - OP_ASSERT, /* Positive lookahead */ - OP_ASSERT_NOT, /* Negative lookahead */ - OP_ASSERTBACK, /* Positive lookbehind */ - OP_ASSERTBACK_NOT, /* Negative lookbehind */ - OP_REVERSE, /* Move pointer back - used in lookbehind assertions */ - - /* ONCE and COND must come after the assertions, with ONCE first, as there's - a test for >= ONCE for a subpattern that isn't an assertion. */ - - OP_ONCE, /* Once matched, don't back up into the subpattern */ - OP_COND, /* Conditional group */ - OP_CREF, /* Used to hold an extraction string number (cond ref) */ - - OP_BRAZERO, /* These two must remain together and in this */ - OP_BRAMINZERO, /* order. */ - - OP_BRANUMBER, /* Used for extracting brackets whose number is greater - than can fit into an opcode. */ - - OP_BRA /* This and greater values are used for brackets that - extract substrings up to a basic limit. After that, - use is made of OP_BRANUMBER. */ -}; + OP_BRAZERO, + OP_BRAMINZERO, -/* The highest extraction number before we have to start using additional -bytes. (Originally PCRE didn't have support for extraction counts highter than -this number.) The value is limited by the number of opcodes left after OP_BRA, -i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional -opcodes. */ + OP_BRANUMBER, -#define EXTRACT_BASIC_MAX 150 + OP_BRA +}; -/* The texts of compile-time error messages are defined as macros here so that -they can be accessed by the POSIX wrapper and converted into error codes. Yes, -I could have used error codes in the first place, but didn't feel like changing -just to accommodate the POSIX wrapper. */ +#define EXTRACT_BASIC_MAX 150 #define ERR1 "\\ at end of pattern" #define ERR2 "\\c at end of pattern" @@ -294,97 +237,71 @@ #define ERR34 "character value in \\x{...} sequence is too large" #define ERR35 "invalid condition (?(0)" -/* All character handling must be done as unsigned characters. Otherwise there -are problems with top-bit-set characters and functions such as isspace(). -However, we leave the interface to the outside world as char *, because that -should make things easier for callers. We define a short type for unsigned char -to save lots of typing. I tried "uchar", but it causes problems on Digital -Unix, where it is defined in sys/types, so use "uschar" instead. */ - typedef unsigned char uschar; -/* The real format of the start of the pcre block; the actual code vector -runs on as long as necessary after the end. */ - -typedef struct real_pcre { - unsigned long int magic_number; - size_t size; - const unsigned char *tables; - unsigned long int options; - unsigned short int top_bracket; - unsigned short int top_backref; - uschar first_char; - uschar req_char; - uschar code[1]; -} real_pcre; - -/* The real format of the extra block returned by pcre_study(). */ - -typedef struct real_pcre_extra { - uschar options; - uschar start_bits[32]; -} real_pcre_extra; - -/* Structure for passing "static" information around between the functions -doing the compiling, so that they are thread-safe. */ +typedef struct pcre_st { + unsigned long int magic_number; + size_t size; + const unsigned char *tables; + unsigned long int options; + unsigned short int top_bracket; + unsigned short int top_backref; + uschar first_char; + uschar req_char; + uschar code[1]; +} pcre_st; + +typedef struct pcre_extra_st { + uschar options; + uschar start_bits[32]; +} pcre_extra_st; typedef struct compile_data { - const uschar *lcc; /* Points to lower casing table */ - const uschar *fcc; /* Points to case-flipping table */ - const uschar *cbits; /* Points to character type table */ - const uschar *ctypes; /* Points to table of type maps */ + const uschar *lcc; + const uschar *fcc; + const uschar *cbits; + const uschar *ctypes; } compile_data; -/* Structure for passing "static" information around between the functions -doing the matching, so that they are thread-safe. */ - typedef struct match_data { - int errorcode; /* As it says */ - int *offset_vector; /* Offset vector */ - int offset_end; /* One past the end */ - int offset_max; /* The maximum usable for return data */ - const uschar *lcc; /* Points to lower casing table */ - const uschar *ctypes; /* Points to table of type maps */ - BOOL offset_overflow; /* Set if too many extractions */ - BOOL notbol; /* NOTBOL flag */ - BOOL noteol; /* NOTEOL flag */ - BOOL utf8; /* UTF8 flag */ - BOOL endonly; /* Dollar not before final \n */ - BOOL notempty; /* Empty string match not wanted */ - const uschar *start_pattern; /* For use when recursing */ - const uschar *start_subject; /* Start of the subject string */ - const uschar *end_subject; - const uschar *start_match; /* Start of this match attempt */ - const uschar *end_match_ptr; /* Subject position at end match */ - int end_offset_top; /* Highwater mark at end of match */ + int errorcode; + int *offset_vector; + int offset_end; + int offset_max; + const uschar *lcc; + const uschar *ctypes; + BOOL offset_overflow; + BOOL notbol; + BOOL noteol; + BOOL utf8; + BOOL endonly; + BOOL notempty; + const uschar *start_pattern; + const uschar *start_subject; + const uschar *end_subject; + const uschar *start_match; + const uschar *end_match_ptr; + int end_offset_top; } match_data; -/* Bit definitions for entries in the pcre_ctypes table. */ - #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 #define ctype_xdigit 0x08 -#define ctype_word 0x10 /* alphameric or '_' */ -#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ +#define ctype_word 0x10 +#define ctype_meta 0x80 -/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set -of bits for a class map. Some classes are built by combining these tables. */ - -#define cbit_space 0 /* [:space:] or \s */ -#define cbit_xdigit 32 /* [:xdigit:] */ -#define cbit_digit 64 /* [:digit:] or \d */ -#define cbit_upper 96 /* [:upper:] */ -#define cbit_lower 128 /* [:lower:] */ -#define cbit_word 160 /* [:word:] or \w */ -#define cbit_graph 192 /* [:graph:] */ -#define cbit_print 224 /* [:print:] */ -#define cbit_punct 256 /* [:punct:] */ -#define cbit_cntrl 288 /* [:cntrl:] */ -#define cbit_length 320 /* Length of the cbits table */ - -/* Offsets of the various tables from the base tables pointer, and -total length. */ +#define cbit_space 0 +#define cbit_xdigit 32 +#define cbit_digit 64 +#define cbit_upper 96 +#define cbit_lower 128 +#define cbit_word 160 +#define cbit_graph 192 +#define cbit_print 224 +#define cbit_punct 256 +#define cbit_cntrl 288 +#define cbit_length 320 #define lcc_offset 0 #define fcc_offset 256 @@ -392,5364 +309,3889 @@ #define ctypes_offset (cbits_offset + cbit_length) #define tables_length (ctypes_offset + 256) -/* ____ END internal.h ____ */ - -#ifndef STR_PCRE_GENTAB - -/* ____ BEGIN pcre.c ____ */ - -/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef -inline, and there are *still* stupid compilers about that don't like indented -pre-processor statements. I suppose it's only been 10 years... */ - -/* Include the internals header, which itself includes Standard C headers plus -the external pcre header. */ - -/* Allow compilation as C++ source code, should anybody want to do that. */ +#ifndef STR_PCRE_TAB #ifdef __cplusplus #define class pcre_class #endif -/* Maximum number of items on the nested bracket stacks at compile time. This -applies to the nesting of all kinds of parentheses. It does not limit -un-nested, non-capturing parentheses. This number can be made bigger if -necessary - it is used to dimension one int and one unsigned char vector at -compile time. */ - #define BRASTACK_SIZE 200 -/* The number of bytes in a literal character string above which we can't add -any more is different when UTF-8 characters may be encountered. */ - #ifdef STR_PCRE_SUPPORT_UTF8 #define MAXLIT 250 #else #define MAXLIT 255 #endif -/* Min and max values for the common repeats; for the maxima, 0 => infinity */ - static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; -/* Text forms of OP_ values and things, for debugging (not all used) */ - -/* Table for handling escaped characters in the range '0'-'z'. Positive returns -are simple data values; negative values are for special things like \d and so -on. Zero means further processing is needed (for things like \x), or the escape -is invalid. */ - static const short int escapes[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ - 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ - '@', -ESC_A, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ - 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ - 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ - 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ - '`', 7, -ESC_b, 0, -ESC_d, ESC_E, ESC_F, 0, /* ` - g */ - 0, 0, 0, 0, 0, 0, ESC_N, 0, /* h - o */ - 0, 0, ESC_R, -ESC_s, ESC_T, 0, 0, -ESC_w, /* p - w */ - 0, 0, -ESC_z /* x - z */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, ':', ';', '<', '=', '>', '?', + '@', -ESC_A, -ESC_B, 0, -ESC_D, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, + 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', + '`', 7, -ESC_b, 0, -ESC_d, ESC_E, ESC_F, 0, + 0, 0, 0, 0, 0, 0, ESC_N, 0, + 0, 0, ESC_R, -ESC_s, ESC_T, 0, 0, -ESC_w, + 0, 0, -ESC_z }; -/* 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, upper, lower, -as this is assumed for handling case independence. */ - static const char *posix_names[] = { - "alpha", "lower", "upper", - "alnum", "ascii", "cntrl", "digit", "graph", - "print", "punct", "space", "word", "xdigit" }; + "alpha", "lower", "upper", + "alnum", "ascii", "cntrl", "digit", "graph", + "print", "punct", "space", "word", "xdigit" +}; static const uschar posix_name_lengths[] = { - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; - -/* Table of class bit maps for each POSIX class; up to three may be combined -to form the class. */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 +}; static const int posix_class_maps[] = { - cbit_lower, cbit_upper, -1, /* alpha */ - cbit_lower, -1, -1, /* lower */ - cbit_upper, -1, -1, /* upper */ - cbit_digit, cbit_lower, cbit_upper, /* alnum */ - cbit_print, cbit_cntrl, -1, /* ascii */ - cbit_cntrl, -1, -1, /* cntrl */ - cbit_digit, -1, -1, /* digit */ - cbit_graph, -1, -1, /* graph */ - cbit_print, -1, -1, /* print */ - cbit_punct, -1, -1, /* punct */ - cbit_space, -1, -1, /* space */ - cbit_word, -1, -1, /* word */ - cbit_xdigit,-1, -1 /* xdigit */ + cbit_lower, cbit_upper, -1, + cbit_lower, -1, -1, + cbit_upper, -1, -1, + cbit_digit, cbit_lower, cbit_upper, + cbit_print, cbit_cntrl, -1, + cbit_cntrl, -1, -1, + cbit_digit, -1, -1, + cbit_graph, -1, -1, + cbit_print, -1, -1, + cbit_punct, -1, -1, + cbit_space, -1, -1, + cbit_word, -1, -1, + cbit_xdigit, -1, -1 }; -/* Definition to allow mutual recursion */ - static BOOL - compile_regex(int, int, int *, uschar **, const uschar **, const char **, - BOOL, int, int *, int *, compile_data *); - -/* Structure for building a chain of data that actually lives on the -stack, for holding the values of the subject pointer at the start of each -subpattern, so as to detect when an empty string has been matched by a -subpattern - to break infinite loops. */ +compile_regex(int, int, int *, uschar **, const uschar **, const char **, + BOOL, int, int *, int *, compile_data *); typedef struct eptrblock { - struct eptrblock *prev; - const uschar *saved_eptr; + struct eptrblock *prev; + const uschar *saved_eptr; } eptrblock; -/* Flag bits for the match() function */ - -#define match_condassert 0x01 /* Called to check a condition assertion */ -#define match_isgroup 0x02 /* Set if start of bracketed group */ +#define match_condassert 0x01 +#define match_isgroup 0x02 -/************************************************* -* Global variables * -*************************************************/ - -/* PCRE is thread-clean and doesn't use any global variables in the normal -sense. However, it calls memory allocation and free functions via the two -indirections below, which are can be changed by the caller, but are shared -between all threads. */ - -void *(*pcre_malloc)(size_t) = malloc; -void (*pcre_free)(void *) = free; - -/************************************************* -* Macros and tables for character handling * -*************************************************/ - -/* 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. */ +void *(*pcre_malloc) (size_t) = malloc; +void (*pcre_free) (void *) = free; #ifndef STR_PCRE_SUPPORT_UTF8 #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; #define BACKCHAR(eptr) -#else /* STR_PCRE_SUPPORT_UTF8 */ - -/* Get the next UTF-8 character, advancing the pointer */ +#else #define GETCHARINC(c, eptr) \ c = *eptr++; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ - int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int s = 6 - a; /* Amount to shift next byte */ \ - c &= utf8_table3[a]; /* Low order bits from first byte */ \ + int a = utf8_table4[c & 0x3f]; \ + int s = 6*a; \ + c = (c & utf8_table3[a]) << s; \ while (a-- > 0) \ { \ + s -= 6; \ c |= (*eptr++ & 0x3f) << s; \ - s += 6; \ } \ } -/* Get the next UTF-8 character, not advancing the pointer, setting length */ - #define GETCHARLEN(c, eptr, len) \ c = *eptr; \ len = 1; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ int i; \ - int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ - int s = 6 - a; /* Amount to shift next byte */ \ - c &= utf8_table3[a]; /* Low order bits from first byte */ \ + int a = utf8_table4[c & 0x3f]; \ + int s = 6*a; \ + c = (c & utf8_table3[a]) << s; \ for (i = 1; i <= a; i++) \ { \ + s -= 6; \ c |= (eptr[i] & 0x3f) << s; \ - s += 6; \ } \ len += a; \ } -/* If the pointer is not at the start of a character, move it back until -it is. */ - #define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--; #endif -/************************************************* -* Default character tables * -*************************************************/ - -/* A default set of character tables is included in the PCRE binary. Its source -is built by the maketables auxiliary program, which uses the default C ctypes -functions, and put in the file chartables.c. These tables are used by PCRE -whenever the caller of pcre_compile() does not provide an alternate set of -tables. */ - -#include "str_pcre_tab.c" +#include "str_pcre.tab" #ifdef STR_PCRE_SUPPORT_UTF8 -/************************************************* -* Tables for UTF-8 support * -*************************************************/ - -/* These are the breakpoints for different numbers of bytes in a UTF-8 -character. */ - -static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; - -/* These are the indicator bits and the mask for the data bits to set in the -first byte of a character, indexed by the number of additional bytes. */ -static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; -static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; +static int utf8_table1[] = + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff }; -/* Table of the number of extra characters, indexed by the first character -masked with 0x3f. The highest number for a valid UTF-8 character is in fact -0x3d. */ +static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc }; +static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; static uschar utf8_table4[] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; - -/************************************************* -* Convert character value to UTF-8 * -*************************************************/ - -/* This function takes an integer value in the range 0 - 0x7fffffff -and encodes it as a UTF-8 character in 0 to 6 bytes. - -Arguments: - cvalue the character value - buffer pointer to buffer for result - at least 6 bytes long - -Returns: number of characters placed in the buffer -*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 +}; -static int -ord2utf8(int cvalue, uschar *buffer) +static int ord2utf8(int cvalue, uschar * buffer) { -register int i, j; -for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) - if (cvalue <= utf8_table1[i]) break; -*buffer++ = utf8_table2[i] | (cvalue & utf8_table3[i]); -cvalue >>= 6 - i; -for (j = 0; j < i; j++) - { - *buffer++ = 0x80 | (cvalue & 0x3f); - cvalue >>= 6; - } -return i + 1; + register int i, j; + for (i = 0; i < sizeof (utf8_table1) / sizeof (int); i++) + if (cvalue <= utf8_table1[i]) + break; + buffer += i; + for (j = i; j > 0; j--) { + *buffer-- = 0x80 | (cvalue & 0x3f); + cvalue >>= 6; + } + *buffer = utf8_table2[i] | cvalue; + return i + 1; } #endif -/************************************************* -* Return version string * -*************************************************/ - #define STRING(a) # a #define XSTRING(s) STRING(s) -const char * -pcre_version(void) +const char *pcre_version(void) { -return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE); + return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE); } -/************************************************* -* (Obsolete) Return info about compiled pattern * -*************************************************/ - -/* This is the original "info" function. It picks potentially useful data out -of the private structure, but its interface was too rigid. It remains for -backwards compatibility. The public options are passed back in an int - though -the re->options field has been expanded to a long int, all the public options -at the low end of it, and so even on 16-bit systems this will still be OK. -Therefore, I haven't changed the API for pcre_info(). - -Arguments: - external_re points to compiled code - optptr where to pass back the options - first_char where to pass back the first character, - or -1 if multiline and all branches start ^, - or -2 otherwise - -Returns: number of capturing subpatterns - or negative values on error -*/ - -int -pcre_info(const pcre *external_re, int *optptr, int *first_char) +int pcre_info(const pcre * external_re, int *optptr, int *first_char) { -const real_pcre *re = (const real_pcre *)external_re; -if (re == NULL) return PCRE_ERROR_NULL; -if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; -if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS); -if (first_char != NULL) - *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : - ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; -return re->top_bracket; + const pcre_st *re = (const pcre_st *)external_re; + if (re == NULL) + return PCRE_ERROR_NULL; + if (re->magic_number != MAGIC_NUMBER) + return PCRE_ERROR_BADMAGIC; + if (optptr != NULL) + *optptr = (int)(re->options & PUBLIC_OPTIONS); + if (first_char != NULL) + *first_char = ((re->options & PCRE_FIRSTSET) != 0) ? re->first_char : + ((re->options & PCRE_STARTLINE) != 0) ? -1 : -2; + return re->top_bracket; } -/************************************************* -* Return info about compiled pattern * -*************************************************/ - -/* This is a newer "info" function which has an extensible interface so -that additional items can be added compatibly. - -Arguments: - external_re points to compiled code - external_study points to study data, or NULL - what what information is required - where where to put the information - -Returns: 0 if data returned, negative on error -*/ - int -pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what, - void *where) +pcre_fullinfo(const pcre * external_re, const pcre_extra * study_data, + int what, void *where) { -const real_pcre *re = (const real_pcre *)external_re; -const real_pcre_extra *study = (const real_pcre_extra *)study_data; - -if (re == NULL || where == NULL) return PCRE_ERROR_NULL; -if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; + const pcre_st *re = (const pcre_st *)external_re; + const pcre_extra_st *study = (const pcre_extra_st *)study_data; -switch (what) - { - case PCRE_INFO_OPTIONS: - *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; - break; - - case PCRE_INFO_SIZE: - *((size_t *)where) = re->size; - break; - - case PCRE_INFO_CAPTURECOUNT: - *((int *)where) = re->top_bracket; - break; - - case PCRE_INFO_BACKREFMAX: - *((int *)where) = re->top_backref; - break; - - case PCRE_INFO_FIRSTCHAR: - *((int *)where) = - ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : - ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; - break; - - case PCRE_INFO_FIRSTTABLE: - *((const uschar **)where) = - (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? - study->start_bits : NULL; - break; - - case PCRE_INFO_LASTLITERAL: - *((int *)where) = - ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1; - break; + if (re == NULL || where == NULL) + return PCRE_ERROR_NULL; + if (re->magic_number != MAGIC_NUMBER) + return PCRE_ERROR_BADMAGIC; + + switch (what) { + case PCRE_INFO_OPTIONS: + *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; + break; + + case PCRE_INFO_SIZE: + *((size_t *) where) = re->size; + break; + + case PCRE_INFO_CAPTURECOUNT: + *((int *)where) = re->top_bracket; + break; + + case PCRE_INFO_BACKREFMAX: + *((int *)where) = re->top_backref; + break; + + case PCRE_INFO_FIRSTCHAR: + *((int *)where) = + ((re->options & PCRE_FIRSTSET) != 0) ? re->first_char : + ((re->options & PCRE_STARTLINE) != 0) ? -1 : -2; + break; + + case PCRE_INFO_FIRSTTABLE: + *((const uschar **)where) = + (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0) ? + study->start_bits : NULL; + break; + + case PCRE_INFO_LASTLITERAL: + *((int *)where) = + ((re->options & PCRE_REQCHSET) != 0) ? re->req_char : -1; + break; + + default: + return PCRE_ERROR_BADOPTION; + } - default: return PCRE_ERROR_BADOPTION; - } - -return 0; + return 0; } -/************************************************* -* Handle escapes * -*************************************************/ - -/* This function is called when a \ has been encountered. It either returns a -positive value for a simple escape such as \n, or a negative value which -encodes one of the more complicated things such as \d. When UTF-8 is enabled, -a positive value greater than 255 may be returned. On entry, ptr is pointing at -the \. On exit, it is on the final character of the escape sequence. - -Arguments: - ptrptr points to the pattern position pointer - errorptr points to the pointer to the error message - bracount number of previous extracting brackets - options the options bits - isclass TRUE if inside a character class - cd pointer to char tables block - -Returns: zero or positive => a data character - negative => a special escape sequence - on error, errorptr is set -*/ - static int -check_escape(const uschar **ptrptr, const char **errorptr, int bracount, - int options, BOOL isclass, compile_data *cd) +check_escape(const uschar ** ptrptr, const char **errorptr, int bracount, + int options, BOOL isclass, compile_data * cd) { -const uschar *ptr = *ptrptr; -int c, i; + const uschar *ptr = *ptrptr; + int c, i; -/* If backslash is at the end of the pattern, it's an error. */ + c = *(++ptr); + if (c == 0) + *errorptr = ERR1; + + else if (c < '0' || c > 'z') { + } + + else if ((i = escapes[c - '0']) != 0) + c = i; + + else { + const uschar *oldptr; + switch (c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + if (!isclass) { + oldptr = ptr; + c -= '0'; + while ((cd->ctypes[ptr[1]] & ctype_digit) != 0) + c = c * 10 + *(++ptr) - '0'; + if (c < 10 || c <= bracount) { + c = -(ESC_REF + c); + break; + } + ptr = oldptr; + } + + if ((c = *ptr) >= '8') { + ptr--; + c = 0; + break; + } + + case '0': + c -= '0'; + while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 && + ptr[1] != '8' && ptr[1] != '9') + c = c * 8 + *(++ptr) - '0'; + c &= 255; + break; -c = *(++ptr); -if (c == 0) *errorptr = ERR1; - -/* Digits or letters may have special meaning; all others are literals. */ - -else if (c < '0' || c > 'z') {} - -/* Do an initial lookup in a table. A non-zero result is something that can be -returned immediately. Otherwise further processing may be required. */ - -else if ((i = escapes[c - '0']) != 0) c = i; - -/* Escapes that need further processing, or are illegal. */ - -else - { - const uschar *oldptr; - switch (c) - { - /* The handling of escape sequences consisting of a string of digits - starting with one that is not zero is not straightforward. By experiment, - the way Perl works seems to be as follows: - - Outside a character class, the digits are read as a decimal number. If the - number is less than 10, or if there are that many previous extracting - left brackets, then it is a back reference. Otherwise, up to three octal - digits are read to form an escaped byte. Thus \123 is likely to be octal - 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal - value is greater than 377, the least significant 8 bits are taken. Inside a - character class, \ followed by a digit is always an octal number. */ - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - - if (!isclass) - { - oldptr = ptr; - c -= '0'; - while ((cd->ctypes[ptr[1]] & ctype_digit) != 0) - c = c * 10 + *(++ptr) - '0'; - if (c < 10 || c <= bracount) - { - c = -(ESC_REF + c); - break; - } - ptr = oldptr; /* Put the pointer back and fall through */ - } - - /* Handle an octal number following \. If the first digit is 8 or 9, Perl - generates a binary zero byte and treats the digit as a following literal. - Thus we have to pull back the pointer by one. */ - - if ((c = *ptr) >= '8') - { - ptr--; - c = 0; - break; - } - - /* \0 always starts an octal number, but we may drop through to here with a - larger first octal digit. */ - - case '0': - c -= '0'; - while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 && - ptr[1] != '8' && ptr[1] != '9') - c = c * 8 + *(++ptr) - '0'; - c &= 255; /* Take least significant 8 bits */ - break; - - /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number - which can be greater than 0xff, but only if the ddd are hex digits. */ - - case 'x': + case 'x': #ifdef STR_PCRE_SUPPORT_UTF8 - if (ptr[1] == '{' && (options & PCRE_UTF8) != 0) - { - const uschar *pt = ptr + 2; - register int count = 0; - c = 0; - while ((cd->ctypes[*pt] & ctype_xdigit) != 0) - { - count++; - c = c * 16 + cd->lcc[*pt] - - (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W'); - pt++; - } - if (*pt == '}') - { - if (c < 0 || count > 8) *errorptr = ERR34; - ptr = pt; - break; - } - /* If the sequence of hex digits does not end with '}', then we don't - recognize this construct; fall through to the normal \x handling. */ - } + if (ptr[1] == '{' && (options & PCRE_UTF8) != 0) { + const uschar *pt = ptr + 2; + register int count = 0; + c = 0; + while ((cd->ctypes[*pt] & ctype_xdigit) != 0) { + count++; + c = c * 16 + cd->lcc[*pt] - + (((cd-> + ctypes[*pt] & ctype_digit) != 0) ? '0' : 'W'); + pt++; + } + if (*pt == '}') { + if (c < 0 || count > 8) + *errorptr = ERR34; + ptr = pt; + break; + } + } #endif - /* Read just a single hex char */ - - c = 0; - while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0) - { - ptr++; - c = c * 16 + cd->lcc[*ptr] - - (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W'); - } - break; - - /* Other special escapes not starting with a digit are straightforward */ - - case 'c': - c = *(++ptr); - if (c == 0) - { - *errorptr = ERR2; - return 0; - } - - /* A letter is upper-cased; then the 0x40 bit is flipped */ - - if (c >= 'a' && c <= 'z') c = cd->fcc[c]; - c ^= 0x40; - break; - - /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any - other alphameric following \ is an error if PCRE_EXTRA was set; otherwise, - for Perl compatibility, it is a literal. This code looks a bit odd, but - there used to be some cases other than the default, and there may be again - in future, so I haven't "optimized" it. */ - - default: - if ((options & PCRE_EXTRA) != 0) switch(c) - { - default: - *errorptr = ERR3; - break; - } - break; - } - } + c = 0; + while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0) { + ptr++; + c = c * 16 + cd->lcc[*ptr] - + (((cd->ctypes[*ptr] & ctype_digit) != 0) ? '0' : 'W'); + } + break; + + case 'c': + c = *(++ptr); + if (c == 0) { + *errorptr = ERR2; + return 0; + } + + if (c >= 'a' && c <= 'z') + c = cd->fcc[c]; + c ^= 0x40; + break; + + default: + if ((options & PCRE_EXTRA) != 0) + switch (c) { + default: + *errorptr = ERR3; + break; + } + break; + } + } -*ptrptr = ptr; -return c; + *ptrptr = ptr; + return c; } -/************************************************* -* Check for counted repeat * -*************************************************/ - -/* This function is called when a '{' is encountered in a place where it might -start a quantifier. It looks ahead to see if it really is a quantifier or not. -It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} -where the ddds are digits. - -Arguments: - p pointer to the first char after '{' - cd pointer to char tables block - -Returns: TRUE or FALSE -*/ - -static BOOL -is_counted_repeat(const uschar *p, compile_data *cd) +static BOOL is_counted_repeat(const uschar * p, compile_data * cd) { -if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; -while ((cd->ctypes[*p] & ctype_digit) != 0) p++; -if (*p == '}') return TRUE; - -if (*p++ != ',') return FALSE; -if (*p == '}') return TRUE; - -if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; -while ((cd->ctypes[*p] & ctype_digit) != 0) p++; -return (*p == '}'); + if ((cd->ctypes[*p++] & ctype_digit) == 0) + return FALSE; + while ((cd->ctypes[*p] & ctype_digit) != 0) + p++; + if (*p == '}') + return TRUE; + + if (*p++ != ',') + return FALSE; + if (*p == '}') + return TRUE; + + if ((cd->ctypes[*p++] & ctype_digit) == 0) + return FALSE; + while ((cd->ctypes[*p] & ctype_digit) != 0) + p++; + return (*p == '}'); } -/************************************************* -* Read repeat counts * -*************************************************/ - -/* Read an item of the form {n,m} and return the values. This is called only -after is_counted_repeat() has confirmed that a repeat-count quantifier exists, -so the syntax is guaranteed to be correct, but we need to check the values. - -Arguments: - p pointer to first char after '{' - minp pointer to int for min - maxp pointer to int for max - returned as -1 if no max - errorptr points to pointer to error message - cd pointer to character tables clock - -Returns: pointer to '}' on success; - current ptr on error, with errorptr set -*/ - -static const uschar * -read_repeat_counts(const uschar *p, int *minp, int *maxp, - const char **errorptr, compile_data *cd) +static const uschar *read_repeat_counts(const uschar * p, int *minp, + int *maxp, const char **errorptr, + compile_data * cd) { -int min = 0; -int max = -1; + int min = 0; + int max = -1; -while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; + while ((cd->ctypes[*p] & ctype_digit) != 0) + min = min * 10 + *p++ - '0'; -if (*p == '}') max = min; else - { - if (*(++p) != '}') - { - max = 0; - while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; - if (max < min) - { - *errorptr = ERR4; - return p; - } - } - } - -/* Do paranoid checks, then fill in the required variables, and pass back the -pointer to the terminating '}'. */ - -if (min > 65535 || max > 65535) - *errorptr = ERR5; -else - { - *minp = min; - *maxp = max; - } -return p; + if (*p == '}') + max = min; + else { + if (*(++p) != '}') { + max = 0; + while ((cd->ctypes[*p] & ctype_digit) != 0) + max = max * 10 + *p++ - '0'; + if (max < min) { + *errorptr = ERR4; + return p; + } + } + } + + if (min > 65535 || max > 65535) + *errorptr = ERR5; + else { + *minp = min; + *maxp = max; + } + return p; } -/************************************************* -* Find the fixed length of a pattern * -*************************************************/ - -/* Scan a pattern and compute the fixed length of subject that will match it, -if the length is fixed. This is needed for dealing with backward assertions. - -Arguments: - code points to the start of the pattern (the bracket) - options the compiling options - -Returns: the fixed length, or -1 if there is no fixed length -*/ - -static int -find_fixedlength(uschar *code, int options) +static int find_fixedlength(uschar * code, int options) { -int length = -1; + int length = -1; -register int branchlength = 0; -register uschar *cc = code + 3; + register int branchlength = 0; + register uschar *cc = code + 3; -/* Scan along the opcodes for this branch. If we get to the end of the -branch, check the length against that of the other branches. */ + for (;;) { + int d; + register int op = *cc; + if (op >= OP_BRA) + op = OP_BRA; + + switch (op) { + case OP_BRA: + case OP_ONCE: + case OP_COND: + d = find_fixedlength(cc, options); + if (d < 0) + return -1; + branchlength += d; + do + cc += (cc[1] << 8) + cc[2]; + while (*cc == OP_ALT); + cc += 3; + break; + + case OP_ALT: + case OP_KET: + case OP_KETRMAX: + case OP_KETRMIN: + case OP_END: + if (length < 0) + length = branchlength; + else if (length != branchlength) + return -1; + if (*cc != OP_ALT) + return length; + cc += 3; + branchlength = 0; + break; + + case OP_ASSERT: + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do + cc += (cc[1] << 8) + cc[2]; + while (*cc == OP_ALT); + cc += 3; + break; + + case OP_REVERSE: + case OP_BRANUMBER: + case OP_CREF: + cc++; + case OP_OPT: + cc++; + case OP_SOD: + case OP_EOD: + case OP_EODN: + case OP_CIRC: + case OP_DOLL: + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + cc++; + break; -for (;;) - { - int d; - register int op = *cc; - if (op >= OP_BRA) op = OP_BRA; - - switch (op) - { - case OP_BRA: - case OP_ONCE: - case OP_COND: - d = find_fixedlength(cc, options); - if (d < 0) return -1; - branchlength += d; - do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); - cc += 3; - break; - - /* Reached end of a branch; if it's a ket it is the end of a nested - call. If it's ALT it is an alternation in a nested call. If it is - END it's the end of the outer call. All can be handled by the same code. */ - - case OP_ALT: - case OP_KET: - case OP_KETRMAX: - case OP_KETRMIN: - case OP_END: - if (length < 0) length = branchlength; - else if (length != branchlength) return -1; - if (*cc != OP_ALT) return length; - cc += 3; - branchlength = 0; - break; - - /* Skip over assertive subpatterns */ - - case OP_ASSERT: - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); - cc += 3; - break; - - /* Skip over things that don't match chars */ - - case OP_REVERSE: - case OP_BRANUMBER: - case OP_CREF: - cc++; - /* Fall through */ - - case OP_OPT: - cc++; - /* Fall through */ - - case OP_SOD: - case OP_EOD: - case OP_EODN: - case OP_CIRC: - case OP_DOLL: - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - cc++; - break; - - /* Handle char strings. In UTF-8 mode we must count characters, not bytes. - This requires a scan of the string, unfortunately. We assume valid UTF-8 - strings, so all we do is reduce the length by one for byte whose bits are - 10xxxxxx. */ - - case OP_CHARS: - branchlength += *(++cc); + case OP_CHARS: + branchlength += *(++cc); #ifdef STR_PCRE_SUPPORT_UTF8 - for (d = 1; d <= *cc; d++) - if ((cc[d] & 0xc0) == 0x80) branchlength--; + for (d = 1; d <= *cc; d++) + if ((cc[d] & 0xc0) == 0x80) + branchlength--; #endif - cc += *cc + 1; - break; - - /* Handle exact repetitions */ + cc += *cc + 1; + break; - case OP_EXACT: - case OP_TYPEEXACT: - branchlength += (cc[1] << 8) + cc[2]; - cc += 4; - break; - - /* Handle single-char matchers */ - - case OP_NOT_DIGIT: - case OP_DIGIT: - case OP_NOT_WHITESPACE: - case OP_WHITESPACE: - case OP_NOT_WORDCHAR: - case OP_WORDCHAR: - case OP_ANY: - branchlength++; - cc++; - break; - - /* Check a class for variable quantification */ - - case OP_CLASS: - cc += 33; - - switch (*cc) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - return -1; - - case OP_CRRANGE: - case OP_CRMINRANGE: - if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1; - branchlength += (cc[1] << 8) + cc[2]; - cc += 5; - break; - - default: - branchlength++; - } - break; - - /* Anything else is variable length */ - - default: - return -1; - } - } -/* Control never gets here */ + case OP_EXACT: + case OP_TYPEEXACT: + branchlength += (cc[1] << 8) + cc[2]; + cc += 4; + break; + + case OP_NOT_DIGIT: + case OP_DIGIT: + case OP_NOT_WHITESPACE: + case OP_WHITESPACE: + case OP_NOT_WORDCHAR: + case OP_WORDCHAR: + case OP_ANY: + branchlength++; + cc++; + break; + + case OP_CLASS: + cc += 33; + + switch (*cc) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + return -1; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) + return -1; + branchlength += (cc[1] << 8) + cc[2]; + cc += 5; + break; + + default: + branchlength++; + } + break; + + default: + return -1; + } + } } -/************************************************* -* Check for POSIX class syntax * -*************************************************/ - -/* This function is called when the sequence "[:" or "[." or "[=" is -encountered in a character class. It checks whether this is followed by an -optional ^ and then a sequence of letters, terminated by a matching ":]" or -".]" or "=]". - -Argument: - ptr pointer to the initial [ - endptr where to return the end pointer - cd pointer to compile data - -Returns: TRUE or FALSE -*/ - static BOOL -check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) +check_posix_syntax(const uschar * ptr, const uschar ** endptr, + compile_data * cd) { -int terminator; /* Don't combine these lines; the Solaris cc */ -terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ -if (*(++ptr) == '^') ptr++; -while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; -if (*ptr == terminator && ptr[1] == ']') - { - *endptr = ptr; - return TRUE; - } -return FALSE; + int terminator; + terminator = *(++ptr); + if (*(++ptr) == '^') + ptr++; + while ((cd->ctypes[*ptr] & ctype_letter) != 0) + ptr++; + if (*ptr == terminator && ptr[1] == ']') { + *endptr = ptr; + return TRUE; + } + return FALSE; } -/************************************************* -* Check POSIX class name * -*************************************************/ - -/* This function is called to check the name given in a POSIX-style class entry -such as [:alnum:]. - -Arguments: - ptr points to the first letter - len the length of the name - -Returns: a value representing the name, or -1 if unknown -*/ - -static int -check_posix_name(const uschar *ptr, int len) +static int check_posix_name(const uschar * ptr, int len) { -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; - yield++; - } -return -1; + 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; + yield++; + } + return -1; } -/************************************************* -* Compile one branch * -*************************************************/ - -/* Scan the pattern, compiling it into the code vector. - -Arguments: - options the option bits - brackets points to number of extracting brackets used - code points to the pointer to the current code point - ptrptr points to the current pattern pointer - errorptr points to pointer to error message - optchanged set to the value of the last OP_OPT item compiled - reqchar set to the last literal character required, else -1 - countlits set to count of mandatory literal characters - cd contains pointers to tables - -Returns: TRUE on success - FALSE, with *errorptr set on error -*/ - static BOOL -compile_branch(int options, int *brackets, uschar **codeptr, - const uschar **ptrptr, const char **errorptr, int *optchanged, - int *reqchar, int *countlits, compile_data *cd) +compile_branch(int options, int *brackets, uschar ** codeptr, + const uschar ** ptrptr, const char **errorptr, int *optchanged, + int *reqchar, int *countlits, compile_data * cd) { -int repeat_type, op_type; -int repeat_min, repeat_max; -int bravalue, length; -int greedy_default, greedy_non_default; -int prevreqchar; -int condcount = 0; -int subcountlits = 0; -register int c; -register uschar *code = *codeptr; -uschar *tempcode; -const uschar *ptr = *ptrptr; -const uschar *tempptr; -uschar *previous = NULL; -uschar class[32]; - -/* Set up the default and non-default settings for greediness */ - -greedy_default = ((options & PCRE_UNGREEDY) != 0); -greedy_non_default = greedy_default ^ 1; - -/* Initialize no required char, and count of literals */ - -*reqchar = prevreqchar = -1; -*countlits = 0; - -/* Switch on next character until the end of the branch */ - -for (;; ptr++) - { - BOOL negate_class; - int class_charcount; - int class_lastchar; - int newoptions; - int skipbytes; - int subreqchar; - - c = *ptr; - if ((options & PCRE_EXTENDED) != 0) - { - if ((cd->ctypes[c] & ctype_space) != 0) continue; - if (c == '#') - { - /* The space before the ; is to avoid a warning on a silly compiler - on the Macintosh. */ - while ((c = *(++ptr)) != 0 && c != '\n') ; - continue; - } - } - - switch(c) - { - /* The branch terminates at end of string, |, or ). */ - - case 0: - case '|': - case ')': - *codeptr = code; - *ptrptr = ptr; - return TRUE; - - /* Handle single-character metacharacters */ - - case '^': - previous = NULL; - *code++ = OP_CIRC; - break; - - case '$': - previous = NULL; - *code++ = OP_DOLL; - break; - - case '.': - previous = code; - *code++ = OP_ANY; - break; - - /* Character classes. These always build a 32-byte bitmap of the permitted - characters, except in the special case where there is only one character. - For negated classes, we build the map as usual, then invert it at the end. - */ - - case '[': - previous = code; - *code++ = OP_CLASS; - - /* If the first character is '^', set the negation flag and skip it. */ - - if ((c = *(++ptr)) == '^') - { - negate_class = TRUE; - c = *(++ptr); - } - else negate_class = FALSE; - - /* Keep a count of chars so that we can optimize the case of just a single - character. */ - - class_charcount = 0; - class_lastchar = -1; - - /* Initialize the 32-char bit map to all zeros. We have to build the - map in a temporary bit of store, in case the class contains only 1 - character, because in that case the compiled code doesn't use the - bit map. */ - - memset(class, 0, 32 * sizeof(uschar)); - - /* Process characters until ] is reached. By writing this as a "do" it - means that an initial ] is taken as a data character. */ - - do - { - if (c == 0) - { - *errorptr = ERR6; - goto FAILED; - } - - /* Handle POSIX class names. Perl allows a negation extension of the - form [:^name]. A square bracket that doesn't match the syntax is - treated as a literal. We also recognize the POSIX constructions - [.ch.] and [=ch=] ("collating elements") and fault them, as Perl - 5.6 does. */ - - if (c == '[' && - (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && - check_posix_syntax(ptr, &tempptr, cd)) - { - BOOL local_negate = FALSE; - int posix_class, i; - register const uschar *cbits = cd->cbits; - - if (ptr[1] != ':') - { - *errorptr = ERR31; - goto FAILED; - } - - ptr += 2; - if (*ptr == '^') - { - local_negate = TRUE; - ptr++; - } - - posix_class = check_posix_name(ptr, tempptr - ptr); - if (posix_class < 0) - { - *errorptr = ERR30; - goto FAILED; - } - - /* If matching is caseless, upper and lower are converted to - alpha. This relies on the fact that the class table starts with - alpha, lower, upper as the first 3 entries. */ - - if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) - posix_class = 0; - - /* Or into the map we are building up to 3 of the static class - tables, or their negations. */ - - posix_class *= 3; - for (i = 0; i < 3; i++) - { - int taboffset = posix_class_maps[posix_class + i]; - if (taboffset < 0) break; - if (local_negate) - for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset]; - else - for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset]; - } - - ptr = tempptr + 1; - class_charcount = 10; /* Set > 1; assumes more than 1 per class */ - continue; - } - - /* Backslash may introduce a single character, or it may introduce one - of the specials, which just set a flag. Escaped items are checked for - validity in the pre-compiling pass. The sequence \b is a special case. - Inside a class (and only there) it is treated as backspace. Elsewhere - it marks a word boundary. Other escapes have preset maps ready to - or into the one we are building. We assume they have more than one - character in them, so set class_count bigger than one. */ - - if (c == '\\') - { - c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); - if (-c == ESC_b) c = '\b'; - else if (c < 0) - { - register const uschar *cbits = cd->cbits; - class_charcount = 10; - switch (-c) - { - case ESC_d: - for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit]; - continue; - - case ESC_D: - for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit]; - continue; - - case ESC_w: - for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word]; - continue; - - case ESC_W: - for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word]; - continue; - - case ESC_s: - for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space]; - continue; - - case ESC_S: - for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space]; - continue; - - default: - *errorptr = ERR7; - goto FAILED; - } - } - - /* Fall through if single character, but don't at present allow - chars > 255 in UTF-8 mode. */ + int repeat_type, op_type; + int repeat_min, repeat_max; + int bravalue, length; + int greedy_default, greedy_non_default; + int prevreqchar; + int condcount = 0; + int subcountlits = 0; + register int c; + register uschar *code = *codeptr; + uschar *tempcode; + const uschar *ptr = *ptrptr; + const uschar *tempptr; + uschar *previous = NULL; + uschar class[32]; + + greedy_default = ((options & PCRE_UNGREEDY) != 0); + greedy_non_default = greedy_default ^ 1; + + *reqchar = prevreqchar = -1; + *countlits = 0; + + for (;; ptr++) { + BOOL negate_class; + int class_charcount; + int class_lastchar; + int newoptions; + int skipbytes; + int subreqchar; + + c = *ptr; + if ((options & PCRE_EXTENDED) != 0) { + if ((cd->ctypes[c] & ctype_space) != 0) + continue; + if (c == '#') { + while ((c = *(++ptr)) != 0 && c != '\n') ; + continue; + } + } + + switch (c) { + case 0: + case '|': + case ')': + *codeptr = code; + *ptrptr = ptr; + return TRUE; + + case '^': + previous = NULL; + *code++ = OP_CIRC; + break; + + case '$': + previous = NULL; + *code++ = OP_DOLL; + break; + + case '.': + previous = code; + *code++ = OP_ANY; + break; + + case '[': + previous = code; + *code++ = OP_CLASS; + + if ((c = *(++ptr)) == '^') { + negate_class = TRUE; + c = *(++ptr); + } + else + negate_class = FALSE; + + class_charcount = 0; + class_lastchar = -1; + + memset(class, 0, 32 * sizeof (uschar)); + + do { + if (c == 0) { + *errorptr = ERR6; + goto FAILED; + } + + if (c == '[' && + (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && + check_posix_syntax(ptr, &tempptr, cd)) { + BOOL local_negate = FALSE; + int posix_class, i; + register const uschar *cbits = cd->cbits; + + if (ptr[1] != ':') { + *errorptr = ERR31; + goto FAILED; + } + + ptr += 2; + if (*ptr == '^') { + local_negate = TRUE; + ptr++; + } + + posix_class = check_posix_name(ptr, tempptr - ptr); + if (posix_class < 0) { + *errorptr = ERR30; + goto FAILED; + } + + if ((options & PCRE_CASELESS) != 0 + && posix_class <= 2) posix_class = 0; + + posix_class *= 3; + for (i = 0; i < 3; i++) { + int taboffset = posix_class_maps[posix_class + i]; + if (taboffset < 0) + break; + if (local_negate) + for (c = 0; c < 32; c++) + class[c] |= ~cbits[c + taboffset]; + else + for (c = 0; c < 32; c++) + class[c] |= cbits[c + taboffset]; + } + + ptr = tempptr + 1; + class_charcount = 10; + continue; + } + + if (c == '\\') { + c = + check_escape(&ptr, errorptr, *brackets, options, + TRUE, cd); + if (-c == ESC_b) + c = '\b'; + else if (c < 0) { + register const uschar *cbits = cd->cbits; + class_charcount = 10; + switch (-c) { + case ESC_d: + for (c = 0; c < 32; c++) + class[c] |= cbits[c + cbit_digit]; + continue; + + case ESC_D: + for (c = 0; c < 32; c++) + class[c] |= ~cbits[c + cbit_digit]; + continue; + + case ESC_w: + for (c = 0; c < 32; c++) + class[c] |= cbits[c + cbit_word]; + continue; + + case ESC_W: + for (c = 0; c < 32; c++) + class[c] |= ~cbits[c + cbit_word]; + continue; + + case ESC_s: + for (c = 0; c < 32; c++) + class[c] |= cbits[c + cbit_space]; + continue; + + case ESC_S: + for (c = 0; c < 32; c++) + class[c] |= ~cbits[c + cbit_space]; + continue; + + default: + *errorptr = ERR7; + goto FAILED; + } + } #ifdef STR_PCRE_SUPPORT_UTF8 - if (c > 255) - { - *errorptr = ERR33; - goto FAILED; - } + if (c > 255) { + *errorptr = ERR33; + goto FAILED; + } #endif - } + } - /* A single character may be followed by '-' to form a range. However, - Perl does not permit ']' to be the end of the range. A '-' character - here is treated as a literal. */ - - if (ptr[1] == '-' && ptr[2] != ']') - { - int d; - ptr += 2; - d = *ptr; - - if (d == 0) - { - *errorptr = ERR6; - goto FAILED; - } - - /* The second part of a range can be a single-character escape, but - not any of the other escapes. Perl 5.6 treats a hyphen as a literal - in such circumstances. */ - - if (d == '\\') - { - const uschar *oldptr = ptr; - d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); + if (ptr[1] == '-' && ptr[2] != ']') { + int d; + ptr += 2; + d = *ptr; + + if (d == 0) { + *errorptr = ERR6; + goto FAILED; + } + + if (d == '\\') { + const uschar *oldptr = ptr; + d = + check_escape(&ptr, errorptr, *brackets, + options, TRUE, cd); #ifdef STR_PCRE_SUPPORT_UTF8 - if (d > 255) - { - *errorptr = ERR33; - goto FAILED; - } + if (d > 255) { + *errorptr = ERR33; + goto FAILED; + } #endif - /* \b is backslash; any other special means the '-' was literal */ - - if (d < 0) - { - if (d == -ESC_b) d = '\b'; else - { - ptr = oldptr - 2; - goto SINGLE_CHARACTER; /* A few lines below */ - } - } - } - - if (d < c) - { - *errorptr = ERR8; - goto FAILED; - } - - for (; c <= d; c++) - { - class[c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - int uc = cd->fcc[c]; /* flip case */ - class[uc/8] |= (1 << (uc&7)); - } - class_charcount++; /* in case a one-char range */ - class_lastchar = c; - } - continue; /* Go get the next char in the class */ - } - - /* Handle a lone single character - we can get here for a normal - non-escape char, or after \ that introduces a single character. */ - - SINGLE_CHARACTER: - - class [c/8] |= (1 << (c&7)); - if ((options & PCRE_CASELESS) != 0) - { - c = cd->fcc[c]; /* flip case */ - class[c/8] |= (1 << (c&7)); - } - class_charcount++; - class_lastchar = c; - } - - /* Loop until ']' reached; the check for end of string happens inside the - loop. This "while" is the end of the "do" above. */ - - while ((c = *(++ptr)) != ']'); - - /* If class_charcount is 1 and class_lastchar is not negative, we saw - precisely one character. This doesn't need the whole 32-byte bit map. - We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if - it's negative. */ - - if (class_charcount == 1 && class_lastchar >= 0) - { - if (negate_class) - { - code[-1] = OP_NOT; - } - else - { - code[-1] = OP_CHARS; - *code++ = 1; - } - *code++ = class_lastchar; - } - - /* Otherwise, negate the 32-byte map if necessary, and copy it into - the code vector. */ - - else - { - if (negate_class) - for (c = 0; c < 32; c++) code[c] = ~class[c]; - else - memcpy(code, class, 32); - code += 32; - } - break; - - /* Various kinds of repeat */ - - case '{': - if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR; - ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd); - if (*errorptr != NULL) goto FAILED; - goto REPEAT; - - case '*': - repeat_min = 0; - repeat_max = -1; - goto REPEAT; - - case '+': - repeat_min = 1; - repeat_max = -1; - goto REPEAT; - - case '?': - repeat_min = 0; - repeat_max = 1; - - REPEAT: - if (previous == NULL) - { - *errorptr = ERR9; - goto FAILED; - } - - /* If the next character is '?' this is a minimizing repeat, by default, - but if PCRE_UNGREEDY is set, it works the other way round. Advance to the - next character. */ - - if (ptr[1] == '?') - { repeat_type = greedy_non_default; ptr++; } - else repeat_type = greedy_default; - - /* If previous was a string of characters, chop off the last one and use it - as the subject of the repeat. If there was only one character, we can - abolish the previous item altogether. A repeat with a zero minimum wipes - out any reqchar setting, backing up to the previous value. We must also - adjust the countlits value. */ - - if (*previous == OP_CHARS) - { - int len = previous[1]; - - if (repeat_min == 0) *reqchar = prevreqchar; - *countlits += repeat_min - 1; - - if (len == 1) - { - c = previous[2]; - code = previous; - } - else - { - c = previous[len+1]; - previous[1]--; - code--; - } - op_type = 0; /* Use single-char op codes */ - goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ - } - - /* If previous was a single negated character ([^a] or similar), we use - one of the special opcodes, replacing it. The code is shared with single- - character repeats by adding a suitable offset into repeat_type. */ - - else if ((int)*previous == OP_NOT) - { - op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ - c = previous[1]; - code = previous; - goto OUTPUT_SINGLE_REPEAT; - } - - /* If previous was a character type match (\d or similar), abolish it and - create a suitable repeat item. The code is shared with single-character - repeats by adding a suitable offset into repeat_type. */ - - else if ((int)*previous < OP_EODN || *previous == OP_ANY) - { - op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ - c = *previous; - code = previous; - - OUTPUT_SINGLE_REPEAT: - - /* If the maximum is zero then the minimum must also be zero; Perl allows - this case, so we do too - by simply omitting the item altogether. */ - - if (repeat_max == 0) goto END_REPEAT; - - /* Combine the op_type with the repeat_type */ - - repeat_type += op_type; - - /* A minimum of zero is handled either as the special case * or ?, or as - an UPTO, with the maximum given. */ - - if (repeat_min == 0) - { - if (repeat_max == -1) *code++ = OP_STAR + repeat_type; - else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; - else - { - *code++ = OP_UPTO + repeat_type; - *code++ = repeat_max >> 8; - *code++ = (repeat_max & 255); - } - } - - /* The case {1,} is handled as the special case + */ - - else if (repeat_min == 1 && repeat_max == -1) - *code++ = OP_PLUS + repeat_type; - - /* The case {n,n} is just an EXACT, while the general case {n,m} is - handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */ - - else - { - if (repeat_min != 1) - { - *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ - *code++ = repeat_min >> 8; - *code++ = (repeat_min & 255); - } - - /* If the mininum is 1 and the previous item was a character string, - we either have to put back the item that got cancelled if the string - length was 1, or add the character back onto the end of a longer - string. For a character type nothing need be done; it will just get - put back naturally. Note that the final character is always going to - get added below. */ - - else if (*previous == OP_CHARS) - { - if (code == previous) code += 2; else previous[1]++; - } - - /* For a single negated character we also have to put back the - item that got cancelled. */ - - else if (*previous == OP_NOT) code++; - - /* 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. */ - - else if (repeat_max != repeat_min) - { - *code++ = c; - repeat_max -= repeat_min; - *code++ = OP_UPTO + repeat_type; - *code++ = repeat_max >> 8; - *code++ = (repeat_max & 255); - } - } - - /* The character or character type itself comes last in all cases. */ - - *code++ = c; - } - - /* If previous was a character class or a back reference, we put the repeat - stuff after it, but just skip the item if the repeat was {0,0}. */ - - else if (*previous == OP_CLASS || *previous == OP_REF) - { - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } - if (repeat_min == 0 && repeat_max == -1) - *code++ = OP_CRSTAR + repeat_type; - else if (repeat_min == 1 && repeat_max == -1) - *code++ = OP_CRPLUS + repeat_type; - else if (repeat_min == 0 && repeat_max == 1) - *code++ = OP_CRQUERY + repeat_type; - else - { - *code++ = OP_CRRANGE + repeat_type; - *code++ = repeat_min >> 8; - *code++ = repeat_min & 255; - if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ - *code++ = repeat_max >> 8; - *code++ = repeat_max & 255; - } - } - - /* If previous was a bracket group, we may have to replicate it in certain - cases. */ - - else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE || - (int)*previous == OP_COND) - { - register int i; - int ketoffset = 0; - int len = code - previous; - uschar *bralink = NULL; - - /* 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 - the final KET, so we can't find the end just by going back from the code - pointer. */ - - if (repeat_max == -1) - { - register uschar *ket = previous; - do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET); - ketoffset = code - ket; - } - - /* The case of a zero minimum is special because of the need to stick - OP_BRAZERO in front of it, and because the group appears once in the - data, whereas in other cases it appears the minimum number of times. For - this reason, it is simplest to treat this case separately, as otherwise - the code gets far too messy. There are several special subcases when the - minimum is zero. */ - - if (repeat_min == 0) - { - /* If we set up a required char from the bracket, we must back off - to the previous value and reset the countlits value too. */ - - if (subcountlits > 0) - { - *reqchar = prevreqchar; - *countlits -= subcountlits; - } - - /* If the maximum is also zero, we just omit the group from the output - altogether. */ - - if (repeat_max == 0) - { - code = previous; - goto END_REPEAT; - } - - /* If the maximum is 1 or unlimited, we just have to stick in the - BRAZERO and do no more at this point. */ - - if (repeat_max <= 1) - { - memmove(previous+1, previous, len); - code++; - *previous++ = OP_BRAZERO + repeat_type; - } - - /* If the maximum is greater than 1 and limited, we have to replicate - in a nested fashion, sticking OP_BRAZERO before each set of brackets. - The first one has to be handled carefully because it's the original - copy, which has to be moved up. The remainder can be handled by code - that is common with the non-zero minimum case below. We just have to - adjust the value or repeat_max, since one less copy is required. */ - - else - { - int offset; - memmove(previous+4, previous, len); - code += 4; - *previous++ = OP_BRAZERO + repeat_type; - *previous++ = OP_BRA; - - /* We chain together the bracket offset fields that have to be - filled in later when the ends of the brackets are reached. */ - - offset = (bralink == NULL)? 0 : previous - bralink; - bralink = previous; - *previous++ = offset >> 8; - *previous++ = offset & 255; - } - - repeat_max--; - } - - /* If the minimum is greater than zero, replicate the group as many - times as necessary, and adjust the maximum to the number of subsequent - copies that we need. */ - - else - { - for (i = 1; i < repeat_min; i++) - { - memcpy(code, previous, len); - code += len; - } - if (repeat_max > 0) repeat_max -= repeat_min; - } - - /* This code is common to both the zero and non-zero minimum cases. If - the maximum is limited, it replicates the group in a nested fashion, - remembering the bracket starts on a stack. In the case of a zero minimum, - the first one was set up above. In all cases the repeat_max now specifies - the number of additional copies needed. */ - - if (repeat_max >= 0) - { - for (i = repeat_max - 1; i >= 0; i--) - { - *code++ = OP_BRAZERO + repeat_type; - - /* All but the final copy start a new nesting, maintaining the - chain of brackets outstanding. */ - - if (i != 0) - { - int offset; - *code++ = OP_BRA; - offset = (bralink == NULL)? 0 : code - bralink; - bralink = code; - *code++ = offset >> 8; - *code++ = offset & 255; - } - - memcpy(code, previous, len); - code += len; - } - - /* Now chain through the pending brackets, and fill in their length - fields (which are holding the chain links pro tem). */ - - while (bralink != NULL) - { - int oldlinkoffset; - int offset = code - bralink + 1; - uschar *bra = code - offset; - oldlinkoffset = (bra[1] << 8) + bra[2]; - bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; - *code++ = OP_KET; - *code++ = bra[1] = offset >> 8; - *code++ = bra[2] = (offset & 255); - } - } - - /* If the maximum is unlimited, set a repeater in the final copy. We - can't just offset backwards from the current code point, because we - don't know if there's been an options resetting after the ket. The - correct offset was computed above. */ - - else code[-ketoffset] = OP_KETRMAX + repeat_type; - } - - /* Else there's some kind of shambles */ - - else - { - *errorptr = ERR11; - goto FAILED; - } - - /* In all case we no longer have a previous item. */ - - END_REPEAT: - previous = NULL; - break; - - /* Start of nested bracket sub-expression, or comment or lookahead or - lookbehind or option setting or condition. First deal with special things - that can come after a bracket; all are introduced by ?, and the appearance - of any of them means that this is not a referencing group. They were - checked for validity in the first pass over the string, so we don't have to - check for syntax errors here. */ - - case '(': - newoptions = options; - skipbytes = 0; - - if (*(++ptr) == '?') - { - int set, unset; - int *optset; - - switch (*(++ptr)) - { - case '#': /* Comment; skip to ket */ - ptr++; - while (*ptr != ')') ptr++; - continue; - - case ':': /* Non-extracting bracket */ - bravalue = OP_BRA; - ptr++; - break; - - case '(': - bravalue = OP_COND; /* Conditional group */ - if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0) - { - int condref = *ptr - '0'; - while (*(++ptr) != ')') condref = condref*10 + *ptr - '0'; - if (condref == 0) - { - *errorptr = ERR35; - goto FAILED; - } - ptr++; - code[3] = OP_CREF; - code[4] = condref >> 8; - code[5] = condref & 255; - skipbytes = 3; - } - else ptr--; - break; - - case '=': /* Positive lookahead */ - bravalue = OP_ASSERT; - ptr++; - break; - - case '!': /* Negative lookahead */ - bravalue = OP_ASSERT_NOT; - ptr++; - break; - - case '<': /* Lookbehinds */ - switch (*(++ptr)) - { - case '=': /* Positive lookbehind */ - bravalue = OP_ASSERTBACK; - ptr++; - break; - - case '!': /* Negative lookbehind */ - bravalue = OP_ASSERTBACK_NOT; - ptr++; - break; - - default: /* Syntax error */ - *errorptr = ERR24; - goto FAILED; - } - break; - - case '>': /* One-time brackets */ - bravalue = OP_ONCE; - ptr++; - break; - - case 'R': /* Pattern recursion */ - *code++ = OP_RECURSE; - ptr++; - continue; - - default: /* Option setting */ - set = unset = 0; - optset = &set; - - while (*ptr != ')' && *ptr != ':') - { - switch (*ptr++) - { - case '-': optset = &unset; break; - - case 'i': *optset |= PCRE_CASELESS; break; - case 'm': *optset |= PCRE_MULTILINE; break; - case 's': *optset |= PCRE_DOTALL; break; - case 'x': *optset |= PCRE_EXTENDED; break; - case 'U': *optset |= PCRE_UNGREEDY; break; - case 'X': *optset |= PCRE_EXTRA; break; - - default: - *errorptr = ERR12; - goto FAILED; - } - } - - /* Set up the changed option bits, but don't change anything yet. */ - - newoptions = (options | set) & (~unset); - - /* If the options ended with ')' this is not the start of a nested - group with option changes, so the options change at this level. At top - level there is nothing else to be done (the options will in fact have - been set from the start of compiling as a result of the first pass) but - at an inner level we must compile code to change the ims options if - necessary, and pass the new setting back so that it can be put at the - start of any following branches, and when this group ends, a resetting - item can be compiled. */ - - if (*ptr == ')') - { - if ((options & PCRE_INGROUP) != 0 && - (options & PCRE_IMS) != (newoptions & PCRE_IMS)) - { - *code++ = OP_OPT; - *code++ = *optchanged = newoptions & PCRE_IMS; - } - options = newoptions; /* Change options at this level */ - previous = NULL; /* This item can't be repeated */ - continue; /* It is complete */ - } - - /* If the options ended with ':' we are heading into a nested group - with possible change of options. Such groups are non-capturing and are - not assertions of any kind. All we need to do is skip over the ':'; - the newoptions value is handled below. */ - - bravalue = OP_BRA; - ptr++; - } - } - - /* Else we have a referencing group; adjust the opcode. If the bracket - number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and - arrange for the true number to follow later, in an OP_BRANUMBER item. */ - - else - { - if (++(*brackets) > EXTRACT_BASIC_MAX) - { - bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; - code[3] = OP_BRANUMBER; - code[4] = *brackets >> 8; - code[5] = *brackets & 255; - skipbytes = 3; - } - else bravalue = OP_BRA + *brackets; - } - - /* Process nested bracketed re. Assertions may not be repeated, but other - kinds can be. We copy code into a non-register variable in order to be able - to pass its address because some compilers complain otherwise. Pass in a - new setting for the ims options if they have changed. */ - - previous = (bravalue >= OP_ONCE)? code : NULL; - *code = bravalue; - tempcode = code; - - if (!compile_regex( - options | PCRE_INGROUP, /* Set for all nested groups */ - ((options & PCRE_IMS) != (newoptions & PCRE_IMS))? - newoptions & PCRE_IMS : -1, /* Pass ims options if changed */ - brackets, /* Extracting bracket count */ - &tempcode, /* Where to put code (updated) */ - &ptr, /* Input pointer (updated) */ - errorptr, /* Where to put an error message */ - (bravalue == OP_ASSERTBACK || - bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ - skipbytes, /* Skip over OP_COND/OP_BRANUMBER */ - &subreqchar, /* For possible last char */ - &subcountlits, /* For literal count */ - cd)) /* Tables block */ - goto FAILED; - - /* At the end of compiling, code is still pointing to the start of the - group, while tempcode has been updated to point past the end of the group - and any option resetting that may follow it. The pattern pointer (ptr) - is on the bracket. */ - - /* If this is a conditional bracket, check that there are no more than - two branches in the group. */ - - else if (bravalue == OP_COND) - { - uschar *tc = code; - condcount = 0; - - do { - condcount++; - tc += (tc[1] << 8) | tc[2]; - } - while (*tc != OP_KET); - - if (condcount > 2) - { - *errorptr = ERR27; - goto FAILED; - } - } - - /* Handle updating of the required character. If the subpattern didn't - set one, leave it as it was. Otherwise, update it for normal brackets of - all kinds, forward assertions, and conditions with two branches. Don't - update the literal count for forward assertions, however. If the bracket - is followed by a quantifier with zero repeat, we have to back off. Hence - the definition of prevreqchar and subcountlits outside the main loop so - that they can be accessed for the back off. */ - - if (subreqchar > 0 && - (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT || - (bravalue == OP_COND && condcount == 2))) - { - prevreqchar = *reqchar; - *reqchar = subreqchar; - if (bravalue != OP_ASSERT) *countlits += subcountlits; - } - - /* Now update the main code pointer to the end of the group. */ - - code = tempcode; - - /* Error if hit end of pattern */ - - if (*ptr != ')') - { - *errorptr = ERR14; - goto FAILED; - } - break; - - /* Check \ for being a real metacharacter; if not, fall through and handle - it as a data character at the start of a string. Escape items are checked - for validity in the pre-compiling pass. */ - - case '\\': - tempptr = ptr; - c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); - - /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values - are arranged to be the negation of the corresponding OP_values. For the - back references, the values are ESC_REF plus the reference number. Only - back references and those types that consume a character may be repeated. - We can test for values between ESC_b and ESC_Z for the latter; this may - have to change if any new ones are ever created. */ - - if (c < 0) - { - if (-c >= ESC_REF) - { - int number = -c - ESC_REF; - previous = code; - *code++ = OP_REF; - *code++ = number >> 8; - *code++ = number & 255; - } - else - { - previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; - *code++ = -c; - } - continue; - } - - /* Data character: reset and fall through */ - - ptr = tempptr; - c = '\\'; - - /* Handle a run of data characters until a metacharacter is encountered. - The first character is guaranteed not to be whitespace or # when the - extended flag is set. */ - - NORMAL_CHAR: - default: - previous = code; - *code = OP_CHARS; - code += 2; - length = 0; - - do - { - if ((options & PCRE_EXTENDED) != 0) - { - if ((cd->ctypes[c] & ctype_space) != 0) continue; - if (c == '#') - { - /* The space before the ; is to avoid a warning on a silly compiler - on the Macintosh. */ - while ((c = *(++ptr)) != 0 && c != '\n') ; - if (c == 0) break; - continue; - } - } - - /* Backslash may introduce a data char or a metacharacter. Escaped items - are checked for validity in the pre-compiling pass. Stop the string - before a metaitem. */ - - if (c == '\\') - { - tempptr = ptr; - c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); - if (c < 0) { ptr = tempptr; break; } - - /* If a character is > 127 in UTF-8 mode, we have to turn it into - two or more characters in the UTF-8 encoding. */ + if (d < 0) { + if (d == -ESC_b) + d = '\b'; + else { + ptr = oldptr - 2; + goto SINGLE_CHARACTER; + } + } + } + + if (d < c) { + *errorptr = ERR8; + goto FAILED; + } + + for (; c <= d; c++) { + class[c / 8] |= (1 << (c & 7)); + if ((options & PCRE_CASELESS) != 0) { + int uc = cd->fcc[c]; + class[uc / 8] |= (1 << (uc & 7)); + } + class_charcount++; + class_lastchar = c; + } + continue; + } + + SINGLE_CHARACTER: + + class[c / 8] |= (1 << (c & 7)); + if ((options & PCRE_CASELESS) != 0) { + c = cd->fcc[c]; + class[c / 8] |= (1 << (c & 7)); + } + class_charcount++; + class_lastchar = c; + } + + while ((c = *(++ptr)) != ']'); + + if (class_charcount == 1 && class_lastchar >= 0) { + if (negate_class) { + code[-1] = OP_NOT; + } + else { + code[-1] = OP_CHARS; + *code++ = 1; + } + *code++ = class_lastchar; + } + + else { + if (negate_class) + for (c = 0; c < 32; c++) + code[c] = ~class[c]; + else + memcpy(code, class, 32); + code += 32; + } + break; + + case '{': + if (!is_counted_repeat(ptr + 1, cd)) + goto NORMAL_CHAR; + ptr = + read_repeat_counts(ptr + 1, &repeat_min, &repeat_max, + errorptr, cd); + if (*errorptr != NULL) + goto FAILED; + goto REPEAT; + + case '*': + repeat_min = 0; + repeat_max = -1; + goto REPEAT; + + case '+': + repeat_min = 1; + repeat_max = -1; + goto REPEAT; + + case '?': + repeat_min = 0; + repeat_max = 1; + + REPEAT: + if (previous == NULL) { + *errorptr = ERR9; + goto FAILED; + } + + if (ptr[1] == '?') { + repeat_type = greedy_non_default; + ptr++; + } + else + repeat_type = greedy_default; + + if (*previous == OP_CHARS) { + int len = previous[1]; + + if (repeat_min == 0) + *reqchar = prevreqchar; + *countlits += repeat_min - 1; + + if (len == 1) { + c = previous[2]; + code = previous; + } + else { + c = previous[len + 1]; + previous[1]--; + code--; + } + op_type = 0; + goto OUTPUT_SINGLE_REPEAT; + } + + else if ((int)*previous == OP_NOT) { + op_type = OP_NOTSTAR - OP_STAR; + c = previous[1]; + code = previous; + goto OUTPUT_SINGLE_REPEAT; + } + + else if ((int)*previous < OP_EODN || *previous == OP_ANY) { + op_type = OP_TYPESTAR - OP_STAR; + c = *previous; + code = previous; + + OUTPUT_SINGLE_REPEAT: + + if (repeat_max == 0) + goto END_REPEAT; + + repeat_type += op_type; + + if (repeat_min == 0) { + if (repeat_max == -1) + *code++ = OP_STAR + repeat_type; + else if (repeat_max == 1) + *code++ = OP_QUERY + repeat_type; + else { + *code++ = OP_UPTO + repeat_type; + *code++ = repeat_max >> 8; + *code++ = (repeat_max & 255); + } + } + + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_PLUS + repeat_type; + + else { + if (repeat_min != 1) { + *code++ = OP_EXACT + op_type; + *code++ = repeat_min >> 8; + *code++ = (repeat_min & 255); + } + + else if (*previous == OP_CHARS) { + if (code == previous) + code += 2; + else + previous[1]++; + } + + else if (*previous == OP_NOT) + code++; + + if (repeat_max < 0) { + *code++ = c; + *code++ = OP_STAR + repeat_type; + } + + else if (repeat_max != repeat_min) { + *code++ = c; + repeat_max -= repeat_min; + *code++ = OP_UPTO + repeat_type; + *code++ = repeat_max >> 8; + *code++ = (repeat_max & 255); + } + } + + *code++ = c; + } + + else if (*previous == OP_CLASS || *previous == OP_REF) { + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + if (repeat_min == 0 && repeat_max == -1) + *code++ = OP_CRSTAR + repeat_type; + else if (repeat_min == 1 && repeat_max == -1) + *code++ = OP_CRPLUS + repeat_type; + else if (repeat_min == 0 && repeat_max == 1) + *code++ = OP_CRQUERY + repeat_type; + else { + *code++ = OP_CRRANGE + repeat_type; + *code++ = repeat_min >> 8; + *code++ = repeat_min & 255; + if (repeat_max == -1) + repeat_max = 0; + *code++ = repeat_max >> 8; + *code++ = repeat_max & 255; + } + } + + else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE + || (int)*previous == OP_COND) { + register int i; + int ketoffset = 0; + int len = code - previous; + uschar *bralink = NULL; + + if (repeat_max == -1) { + register uschar *ket = previous; + do + ket += (ket[1] << 8) + ket[2]; + while (*ket != OP_KET); + ketoffset = code - ket; + } + + if (repeat_min == 0) { + if (subcountlits > 0) { + *reqchar = prevreqchar; + *countlits -= subcountlits; + } + + if (repeat_max == 0) { + code = previous; + goto END_REPEAT; + } + + if (repeat_max <= 1) { + memmove(previous + 1, previous, len); + code++; + *previous++ = OP_BRAZERO + repeat_type; + } + + else { + int offset; + memmove(previous + 4, previous, len); + code += 4; + *previous++ = OP_BRAZERO + repeat_type; + *previous++ = OP_BRA; + + offset = + (bralink == NULL) ? 0 : previous - bralink; + bralink = previous; + *previous++ = offset >> 8; + *previous++ = offset & 255; + } + + repeat_max--; + } + + else { + for (i = 1; i < repeat_min; i++) { + memcpy(code, previous, len); + code += len; + } + if (repeat_max > 0) + repeat_max -= repeat_min; + } + + if (repeat_max >= 0) { + for (i = repeat_max - 1; i >= 0; i--) { + *code++ = OP_BRAZERO + repeat_type; + + if (i != 0) { + int offset; + *code++ = OP_BRA; + offset = + (bralink == NULL) ? 0 : code - bralink; + bralink = code; + *code++ = offset >> 8; + *code++ = offset & 255; + } + + memcpy(code, previous, len); + code += len; + } + + while (bralink != NULL) { + int oldlinkoffset; + int offset = code - bralink + 1; + uschar *bra = code - offset; + oldlinkoffset = (bra[1] << 8) + bra[2]; + bralink = + (oldlinkoffset == + 0) ? NULL : bralink - oldlinkoffset; + *code++ = OP_KET; + *code++ = bra[1] = offset >> 8; + *code++ = bra[2] = (offset & 255); + } + } + + else + code[-ketoffset] = OP_KETRMAX + repeat_type; + } + + else { + *errorptr = ERR11; + goto FAILED; + } + + END_REPEAT: + previous = NULL; + break; + + case '(': + newoptions = options; + skipbytes = 0; + + if (*(++ptr) == '?') { + int set, unset; + int *optset; + + switch (*(++ptr)) { + case '#': + ptr++; + while (*ptr != ')') + ptr++; + continue; + + case ':': + bravalue = OP_BRA; + ptr++; + break; + + case '(': + bravalue = OP_COND; + if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0) { + int condref = *ptr - '0'; + while (*(++ptr) != ')') + condref = condref * 10 + *ptr - '0'; + if (condref == 0) { + *errorptr = ERR35; + goto FAILED; + } + ptr++; + code[3] = OP_CREF; + code[4] = condref >> 8; + code[5] = condref & 255; + skipbytes = 3; + } + else + ptr--; + break; + + case '=': + bravalue = OP_ASSERT; + ptr++; + break; + + case '!': + bravalue = OP_ASSERT_NOT; + ptr++; + break; + + case '<': + switch (*(++ptr)) { + case '=': + bravalue = OP_ASSERTBACK; + ptr++; + break; + + case '!': + bravalue = OP_ASSERTBACK_NOT; + ptr++; + break; + + default: + *errorptr = ERR24; + goto FAILED; + } + break; + + case '>': + bravalue = OP_ONCE; + ptr++; + break; + + case 'R': + *code++ = OP_RECURSE; + ptr++; + continue; + + default: + set = unset = 0; + optset = &set; + + while (*ptr != ')' && *ptr != ':') { + switch (*ptr++) { + case '-': + optset = &unset; + break; + + case 'i': + *optset |= PCRE_CASELESS; + break; + case 'm': + *optset |= PCRE_MULTILINE; + break; + case 's': + *optset |= PCRE_DOTALL; + break; + case 'x': + *optset |= PCRE_EXTENDED; + break; + case 'U': + *optset |= PCRE_UNGREEDY; + break; + case 'X': + *optset |= PCRE_EXTRA; + break; + + default: + *errorptr = ERR12; + goto FAILED; + } + } + + newoptions = (options | set) & (~unset); + + if (*ptr == ')') { + if ((options & PCRE_INGROUP) != 0 && + (options & PCRE_IMS) != + (newoptions & PCRE_IMS)) { + *code++ = OP_OPT; + *code++ = *optchanged = + newoptions & PCRE_IMS; + } + options = newoptions; + previous = NULL; + continue; + } + + bravalue = OP_BRA; + ptr++; + } + } + + else { + if (++(*brackets) > EXTRACT_BASIC_MAX) { + bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; + code[3] = OP_BRANUMBER; + code[4] = *brackets >> 8; + code[5] = *brackets & 255; + skipbytes = 3; + } + else + bravalue = OP_BRA + *brackets; + } + + previous = (bravalue >= OP_ONCE) ? code : NULL; + *code = bravalue; + tempcode = code; + + if (!compile_regex(options | PCRE_INGROUP, + ((options & PCRE_IMS) != + (newoptions & PCRE_IMS)) ? newoptions & + PCRE_IMS : -1, brackets, &tempcode, &ptr, + errorptr, (bravalue == OP_ASSERTBACK + || bravalue == + OP_ASSERTBACK_NOT), skipbytes, + &subreqchar, &subcountlits, + cd)) goto FAILED; + + else if (bravalue == OP_COND) { + uschar *tc = code; + condcount = 0; + + do { + condcount++; + tc += (tc[1] << 8) | tc[2]; + } + while (*tc != OP_KET); + + if (condcount > 2) { + *errorptr = ERR27; + goto FAILED; + } + } + + if (subreqchar > 0 && + (bravalue >= OP_BRA || bravalue == OP_ONCE + || bravalue == OP_ASSERT || (bravalue == OP_COND + && condcount == 2))) { + prevreqchar = *reqchar; + *reqchar = subreqchar; + if (bravalue != OP_ASSERT) + *countlits += subcountlits; + } + + code = tempcode; + + if (*ptr != ')') { + *errorptr = ERR14; + goto FAILED; + } + break; + + case '\\': + tempptr = ptr; + c = + check_escape(&ptr, errorptr, *brackets, options, FALSE, + cd); + + if (c < 0) { + if (-c >= ESC_REF) { + int number = -c - ESC_REF; + previous = code; + *code++ = OP_REF; + *code++ = number >> 8; + *code++ = number & 255; + } + else { + previous = (-c > ESC_b && -c < ESC_Z) ? code : NULL; + *code++ = -c; + } + continue; + } + + ptr = tempptr; + c = '\\'; + + NORMAL_CHAR: + default: + previous = code; + *code = OP_CHARS; + code += 2; + length = 0; + + do { + if ((options & PCRE_EXTENDED) != 0) { + if ((cd->ctypes[c] & ctype_space) != 0) + continue; + if (c == '#') { + while ((c = *(++ptr)) != 0 && c != '\n') ; + if (c == 0) + break; + continue; + } + } + + if (c == '\\') { + tempptr = ptr; + c = + check_escape(&ptr, errorptr, *brackets, options, + FALSE, cd); + if (c < 0) { + ptr = tempptr; + break; + } #ifdef STR_PCRE_SUPPORT_UTF8 - if (c > 127 && (options & PCRE_UTF8) != 0) - { - uschar buffer[8]; - int len = ord2utf8(c, buffer); - for (c = 0; c < len; c++) *code++ = buffer[c]; - length += len; - continue; - } + if (c > 127 && (options & PCRE_UTF8) != 0) { + uschar buffer[8]; + int len = ord2utf8(c, buffer); + for (c = 0; c < len; c++) + *code++ = buffer[c]; + length += len; + continue; + } #endif - } - - /* Ordinary character or single-char escape */ - - *code++ = c; - length++; - } - - /* This "while" is the end of the "do" above. */ - - while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); - - /* Update the last character and the count of literals */ + } - prevreqchar = (length > 1)? code[-2] : *reqchar; - *reqchar = code[-1]; - *countlits += length; - - /* Compute the length and set it in the data vector, and advance to - the next state. */ - - previous[1] = length; - if (length < MAXLIT) ptr--; - break; - } - } /* end of big loop */ - -/* Control never reaches here by falling through, only by a goto for all the -error states. Pass back the position in the pattern so that it can be displayed -to the user for diagnosing the error. */ - -FAILED: -*ptrptr = ptr; -return FALSE; + *code++ = c; + length++; + } + + while (length < MAXLIT + && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); + + prevreqchar = (length > 1) ? code[-2] : *reqchar; + *reqchar = code[-1]; + *countlits += length; + + previous[1] = length; + if (length < MAXLIT) + ptr--; + break; + } + } + + FAILED: + *ptrptr = ptr; + return FALSE; } -/************************************************* -* Compile sequence of alternatives * -*************************************************/ - -/* On entry, ptr is pointing past the bracket character, but on return -it points to the closing bracket, or vertical bar, or end of string. -The code variable is pointing at the byte into which the BRA operator has been -stored. If the ims options are changed at the start (for a (?ims: group) or -during any branch, we need to insert an OP_OPT item at the start of every -following branch to ensure they get set correctly at run time, and also pass -the new options into every subsequent branch compile. - -Argument: - options the option bits - optchanged new ims options to set as if (?ims) were at the start, or -1 - for no change - brackets -> int containing the number of extracting brackets used - codeptr -> the address of the current code pointer - ptrptr -> the address of the current pattern pointer - errorptr -> pointer to error message - lookbehind TRUE if this is a lookbehind assertion - skipbytes skip this many bytes at start (for OP_COND, OP_BRANUMBER) - reqchar -> place to put the last required character, or a negative number - countlits -> place to put the shortest literal count of any branch - cd points to the data block with tables pointers - -Returns: TRUE on success -*/ - static BOOL -compile_regex(int options, int optchanged, int *brackets, uschar **codeptr, - const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes, - int *reqchar, int *countlits, compile_data *cd) +compile_regex(int options, int optchanged, int *brackets, uschar ** codeptr, + const uschar ** ptrptr, const char **errorptr, BOOL lookbehind, + int skipbytes, int *reqchar, int *countlits, compile_data * cd) { -const uschar *ptr = *ptrptr; -uschar *code = *codeptr; -uschar *last_branch = code; -uschar *start_bracket = code; -uschar *reverse_count = NULL; -int oldoptions = options & PCRE_IMS; -int branchreqchar, branchcountlits; - -*reqchar = -1; -*countlits = INT_MAX; -code += 3 + skipbytes; - -/* Loop for each alternative branch */ - -for (;;) - { - int length; - - /* Handle change of options */ - - if (optchanged >= 0) - { - *code++ = OP_OPT; - *code++ = optchanged; - options = (options & ~PCRE_IMS) | optchanged; - } - - /* Set up dummy OP_REVERSE if lookbehind assertion */ - - if (lookbehind) - { - *code++ = OP_REVERSE; - reverse_count = code; - *code++ = 0; - *code++ = 0; - } - - /* Now compile the branch */ - - if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged, - &branchreqchar, &branchcountlits, cd)) - { - *ptrptr = ptr; - return FALSE; - } - - /* Fill in the length of the last branch */ - - length = code - last_branch; - last_branch[1] = length >> 8; - last_branch[2] = length & 255; - - /* Save the last required character if all branches have the same; a current - value of -1 means unset, while -2 means "previous branch had no last required - char". */ - - if (*reqchar != -2) - { - if (branchreqchar >= 0) - { - if (*reqchar == -1) *reqchar = branchreqchar; - else if (*reqchar != branchreqchar) *reqchar = -2; - } - else *reqchar = -2; - } - - /* Keep the shortest literal count */ - - if (branchcountlits < *countlits) *countlits = branchcountlits; - - /* If lookbehind, check that this branch matches a fixed-length string, - and put the length into the OP_REVERSE item. Temporarily mark the end of - the branch with OP_END. */ - - if (lookbehind) - { - *code = OP_END; - length = find_fixedlength(last_branch, options); - - if (length < 0) - { - *errorptr = ERR25; - *ptrptr = ptr; - return FALSE; - } - reverse_count[0] = (length >> 8); - reverse_count[1] = length & 255; - } - - /* Reached end of expression, either ')' or end of pattern. Insert a - terminating ket and the length of the whole bracketed item, and return, - leaving the pointer at the terminating char. If any of the ims options - were changed inside the group, compile a resetting op-code following. */ - - if (*ptr != '|') - { - length = code - start_bracket; - *code++ = OP_KET; - *code++ = length >> 8; - *code++ = length & 255; - if (optchanged >= 0) - { - *code++ = OP_OPT; - *code++ = oldoptions; - } - *codeptr = code; - *ptrptr = ptr; - return TRUE; - } - - /* Another branch follows; insert an "or" node and advance the pointer. */ - - *code = OP_ALT; - last_branch = code; - code += 3; - ptr++; - } -/* Control never reaches here */ + const uschar *ptr = *ptrptr; + uschar *code = *codeptr; + uschar *last_branch = code; + uschar *start_bracket = code; + uschar *reverse_count = NULL; + int oldoptions = options & PCRE_IMS; + int branchreqchar, branchcountlits; + + *reqchar = -1; + *countlits = INT_MAX; + code += 3 + skipbytes; + + for (;;) { + int length; + + if (optchanged >= 0) { + *code++ = OP_OPT; + *code++ = optchanged; + options = (options & ~PCRE_IMS) | optchanged; + } + + if (lookbehind) { + *code++ = OP_REVERSE; + reverse_count = code; + *code++ = 0; + *code++ = 0; + } + + if (!compile_branch + (options, brackets, &code, &ptr, errorptr, &optchanged, + &branchreqchar, &branchcountlits, cd)) { + *ptrptr = ptr; + return FALSE; + } + + length = code - last_branch; + last_branch[1] = length >> 8; + last_branch[2] = length & 255; + + if (*reqchar != -2) { + if (branchreqchar >= 0) { + if (*reqchar == -1) + *reqchar = branchreqchar; + else if (*reqchar != branchreqchar) + *reqchar = -2; + } + else + *reqchar = -2; + } + + if (branchcountlits < *countlits) + *countlits = branchcountlits; + + if (lookbehind) { + *code = OP_END; + length = find_fixedlength(last_branch, options); + + if (length < 0) { + *errorptr = ERR25; + *ptrptr = ptr; + return FALSE; + } + reverse_count[0] = (length >> 8); + reverse_count[1] = length & 255; + } + + if (*ptr != '|') { + length = code - start_bracket; + *code++ = OP_KET; + *code++ = length >> 8; + *code++ = length & 255; + if (optchanged >= 0) { + *code++ = OP_OPT; + *code++ = oldoptions; + } + *codeptr = code; + *ptrptr = ptr; + return TRUE; + } + + *code = OP_ALT; + last_branch = code; + code += 3; + ptr++; + } } -/************************************************* -* Find first significant op code * -*************************************************/ - -/* This is called by several functions that scan a compiled expression looking -for a fixed first character, or an anchoring op code etc. It skips over things -that do not influence this. For one application, a change of caseless option is -important. - -Arguments: - code pointer to the start of the group - options pointer to external options - optbit the option bit whose changing is significant, or - zero if none are - optstop TRUE to return on option change, otherwise change the options - value and continue - -Returns: pointer to the first significant opcode -*/ - -static const uschar* -first_significant_code(const uschar *code, int *options, int optbit, - BOOL optstop) +static const uschar *first_significant_code(const uschar * code, int *options, + int optbit, BOOL optstop) { -for (;;) - { - switch ((int)*code) - { - case OP_OPT: - if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) - { - if (optstop) return code; - *options = (int)code[1]; - } - code += 2; - break; - - case OP_CREF: - case OP_BRANUMBER: - code += 3; - break; - - case OP_WORD_BOUNDARY: - case OP_NOT_WORD_BOUNDARY: - code++; - break; - - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do code += (code[1] << 8) + code[2]; while (*code == OP_ALT); - code += 3; - break; - - default: - return code; - } - } -/* Control never reaches here */ + for (;;) { + switch ((int)*code) { + case OP_OPT: + if (optbit > 0 + && ((int)code[1] & optbit) != (*options & optbit)) { + if (optstop) + return code; + *options = (int)code[1]; + } + code += 2; + break; + + case OP_CREF: + case OP_BRANUMBER: + code += 3; + break; + + case OP_WORD_BOUNDARY: + case OP_NOT_WORD_BOUNDARY: + code++; + break; + + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do + code += (code[1] << 8) + code[2]; + while (*code == OP_ALT); + code += 3; + break; + + default: + return code; + } + } } -/************************************************* -* Check for anchored expression * -*************************************************/ - -/* Try to find out if this is an anchored regular expression. Consider each -alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket -all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then -it's anchored. However, if this is a multiline pattern, then only OP_SOD -counts, since OP_CIRC can match in the middle. - -A branch is also implicitly anchored if it starts with .* and DOTALL is set, -because that will try the rest of the pattern at all possible matching points, -so there is no point trying them again. - -Arguments: - code points to start of expression (the bracket) - options points to the options setting - -Returns: TRUE or FALSE -*/ - -static BOOL -is_anchored(register const uschar *code, int *options) +static BOOL is_anchored(register const uschar * code, int *options) { -do { - const uschar *scode = first_significant_code(code + 3, options, - PCRE_MULTILINE, FALSE); - register int op = *scode; - if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) - { if (!is_anchored(scode, options)) return FALSE; } - else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && - (*options & PCRE_DOTALL) != 0) - { if (scode[1] != OP_ANY) return FALSE; } - else if (op != OP_SOD && - ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) - return FALSE; - code += (code[1] << 8) + code[2]; - } -while (*code == OP_ALT); -return TRUE; + do { + const uschar *scode = first_significant_code(code + 3, options, + PCRE_MULTILINE, FALSE); + register int op = *scode; + if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { + if (!is_anchored(scode, options)) + return FALSE; + } + else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && + (*options & PCRE_DOTALL) != 0) { + if (scode[1] != OP_ANY) + return FALSE; + } + else if (op != OP_SOD && + ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) + return FALSE; + code += (code[1] << 8) + code[2]; + } + while (*code == OP_ALT); + return TRUE; } -/************************************************* -* Check for starting with ^ or .* * -*************************************************/ - -/* This is called to find out if every branch starts with ^ or .* so that -"first char" processing can be done to speed things up in multiline -matching and for non-DOTALL patterns that start with .* (which must start at -the beginning or after \n). - -Argument: points to start of expression (the bracket) -Returns: TRUE or FALSE -*/ - -static BOOL -is_startline(const uschar *code) +static BOOL is_startline(const uschar * code) { -do { - const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE); - register int op = *scode; - if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) - { if (!is_startline(scode)) return FALSE; } - else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) - { if (scode[1] != OP_ANY) return FALSE; } - else if (op != OP_CIRC) return FALSE; - code += (code[1] << 8) + code[2]; - } -while (*code == OP_ALT); -return TRUE; + do { + const uschar *scode = + first_significant_code(code + 3, NULL, 0, FALSE); + register int op = *scode; + if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { + if (!is_startline(scode)) + return FALSE; + } + else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) { + if (scode[1] != OP_ANY) + return FALSE; + } + else if (op != OP_CIRC) + return FALSE; + code += (code[1] << 8) + code[2]; + } + while (*code == OP_ALT); + return TRUE; } -/************************************************* -* Check for fixed first char * -*************************************************/ - -/* Try to find out if there is a fixed first character. This is called for -unanchored expressions, as it speeds up their processing quite considerably. -Consider each alternative branch. If they all start with the same char, or with -a bracket all of whose alternatives start with the same char (recurse ad lib), -then we return that char, otherwise -1. - -Arguments: - code points to start of expression (the bracket) - options pointer to the options (used to check casing changes) - -Returns: -1 or the fixed first char -*/ - -static int -find_firstchar(const uschar *code, int *options) +static int find_firstchar(const uschar * code, int *options) { -register int c = -1; -do { - int d; - const uschar *scode = first_significant_code(code + 3, options, - PCRE_CASELESS, TRUE); - register int op = *scode; - - if (op >= OP_BRA) op = OP_BRA; - - switch(op) - { - default: - return -1; - - case OP_BRA: - case OP_ASSERT: - case OP_ONCE: - case OP_COND: - if ((d = find_firstchar(scode, options)) < 0) return -1; - if (c < 0) c = d; else if (c != d) return -1; - break; - - case OP_EXACT: /* Fall through */ - scode++; - - case OP_CHARS: /* Fall through */ - scode++; - - case OP_PLUS: - case OP_MINPLUS: - if (c < 0) c = scode[1]; else if (c != scode[1]) return -1; - break; - } - - code += (code[1] << 8) + code[2]; - } -while (*code == OP_ALT); -return c; + register int c = -1; + do { + int d; + const uschar *scode = first_significant_code(code + 3, options, + PCRE_CASELESS, TRUE); + register int op = *scode; + + if (op >= OP_BRA) + op = OP_BRA; + + switch (op) { + default: + return -1; + + case OP_BRA: + case OP_ASSERT: + case OP_ONCE: + case OP_COND: + if ((d = find_firstchar(scode, options)) < 0) + return -1; + if (c < 0) + c = d; + else if (c != d) + return -1; + break; + + case OP_EXACT: + scode++; + + case OP_CHARS: + scode++; + + case OP_PLUS: + case OP_MINPLUS: + if (c < 0) + c = scode[1]; + else if (c != scode[1]) + return -1; + break; + } + + code += (code[1] << 8) + code[2]; + } + while (*code == OP_ALT); + return c; } -/************************************************* -* Compile a Regular Expression * -*************************************************/ - -/* This function takes a string and returns a pointer to a block of store -holding a compiled version of the expression. - -Arguments: - pattern the regular expression - options various option bits - errorptr pointer to pointer to error text - erroroffset ptr offset in pattern where error was detected - tables pointer to character tables or NULL - -Returns: pointer to compiled data block, or NULL on error, - with errorptr and erroroffset set -*/ - -pcre * -pcre_compile(const char *pattern, int options, const char **errorptr, - int *erroroffset, const unsigned char *tables) +pcre *pcre_compile(const char *pattern, int options, const char **errorptr, + int *erroroffset, const unsigned char *tables) { -real_pcre *re; -int length = 3; /* For initial BRA plus length */ -int runlength; -int c, reqchar, countlits; -int bracount = 0; -int top_backref = 0; -int branch_extra = 0; -int branch_newextra; -unsigned int brastackptr = 0; -size_t size; -uschar *code; -const uschar *ptr; -compile_data compile_block; -int brastack[BRASTACK_SIZE]; -uschar bralenstack[BRASTACK_SIZE]; - -/* Can't support UTF8 unless PCRE has been compiled to include the code. */ + pcre_st *re; + int length = 3; + int runlength; + int c, reqchar, countlits; + int bracount = 0; + int top_backref = 0; + int branch_extra = 0; + int branch_newextra; + unsigned int brastackptr = 0; + size_t size; + uschar *code; + const uschar *ptr; + compile_data compile_block; + int brastack[BRASTACK_SIZE]; + uschar bralenstack[BRASTACK_SIZE]; #ifndef STR_PCRE_SUPPORT_UTF8 -if ((options & PCRE_UTF8) != 0) - { - *errorptr = ERR32; - return NULL; - } + if ((options & PCRE_UTF8) != 0) { + *errorptr = ERR32; + return NULL; + } #endif -/* We can't pass back an error message if errorptr is NULL; I guess the best we -can do is just return NULL. */ - -if (errorptr == NULL) return NULL; -*errorptr = NULL; - -/* However, we can give a message for this error */ - -if (erroroffset == NULL) - { - *errorptr = ERR16; - return NULL; - } -*erroroffset = 0; - -if ((options & ~PUBLIC_OPTIONS) != 0) - { - *errorptr = ERR17; - return NULL; - } - -/* Set up pointers to the individual character tables */ - -if (tables == NULL) tables = pcre_default_tables; -compile_block.lcc = tables + lcc_offset; -compile_block.fcc = tables + fcc_offset; -compile_block.cbits = tables + cbits_offset; -compile_block.ctypes = tables + ctypes_offset; - -/* Reflect pattern for debugging output */ - -/* The first thing to do is to make a pass over the pattern to compute the -amount of store required to hold the compiled code. This does not have to be -perfect as long as errors are overestimates. At the same time we can detect any -internal flag settings. Make an attempt to correct for any counted white space -if an "extended" flag setting appears late in the pattern. We can't be so -clever for #-comments. */ - -ptr = (const uschar *)(pattern - 1); -while ((c = *(++ptr)) != 0) - { - int min, max; - int class_charcount; - int bracket_length; - - if ((options & PCRE_EXTENDED) != 0) - { - if ((compile_block.ctypes[c] & ctype_space) != 0) continue; - if (c == '#') - { - /* The space before the ; is to avoid a warning on a silly compiler - on the Macintosh. */ - while ((c = *(++ptr)) != 0 && c != '\n') ; - continue; - } - } - - switch(c) - { - /* A backslashed item may be an escaped "normal" character or a - character type. For a "normal" character, put the pointers and - character back so that tests for whitespace etc. in the input - are done correctly. */ - - case '\\': - { - const uschar *save_ptr = ptr; - c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if (c >= 0) - { - ptr = save_ptr; - c = '\\'; - goto NORMAL_CHAR; - } - } - length++; - - /* A back reference needs an additional 2 bytes, plus either one or 5 - bytes for a repeat. We also need to keep the value of the highest - back reference. */ - - if (c <= -ESC_REF) - { - int refnum = -c - ESC_REF; - if (refnum > top_backref) top_backref = refnum; - length += 2; /* For single back reference */ - if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) - { - ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if ((min == 0 && (max == 1 || max == -1)) || - (min == 1 && max == -1)) - length++; - else length += 5; - if (ptr[1] == '?') ptr++; - } - } - continue; - - case '^': - case '.': - case '$': - case '*': /* These repeats won't be after brackets; */ - case '+': /* those are handled separately */ - case '?': - length++; - continue; - - /* This covers the cases of repeats after a single char, metachar, class, - or back reference. */ - - case '{': - if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR; - ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if ((min == 0 && (max == 1 || max == -1)) || - (min == 1 && max == -1)) - length++; - else - { - length--; /* Uncount the original char or metachar */ - if (min == 1) length++; else if (min > 0) length += 4; - if (max > 0) length += 4; else length += 2; - } - if (ptr[1] == '?') ptr++; - continue; - - /* An alternation contains an offset to the next branch or ket. If any ims - options changed in the previous branch(es), and/or if we are in a - lookbehind assertion, extra space will be needed at the start of the - branch. This is handled by branch_extra. */ - - case '|': - length += 3 + branch_extra; - continue; - - /* A character class uses 33 characters. Don't worry about character types - that aren't allowed in classes - they'll get picked up during the compile. - A character class that contains only one character uses 2 or 3 bytes, - depending on whether it is negated or not. Notice this where we can. */ - - case '[': - class_charcount = 0; - if (*(++ptr) == '^') ptr++; - do - { - if (*ptr == '\\') - { - int ch = check_escape(&ptr, errorptr, bracount, options, TRUE, - &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if (-ch == ESC_b) class_charcount++; else class_charcount = 10; - } - else class_charcount++; - ptr++; - } - while (*ptr != 0 && *ptr != ']'); - - /* Repeats for negated single chars are handled by the general code */ - - if (class_charcount == 1) length += 3; else - { - length += 33; - - /* A repeat needs either 1 or 5 bytes. */ - - if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) - { - ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if ((min == 0 && (max == 1 || max == -1)) || - (min == 1 && max == -1)) - length++; - else length += 5; - if (ptr[1] == '?') ptr++; - } - } - continue; - - /* Brackets may be genuine groups or special things */ - - case '(': - branch_newextra = 0; - bracket_length = 3; - - /* Handle special forms of bracket, which all start (? */ - - if (ptr[1] == '?') - { - int set, unset; - int *optset; - - switch (c = ptr[2]) - { - /* Skip over comments entirely */ - case '#': - ptr += 3; - while (*ptr != 0 && *ptr != ')') ptr++; - if (*ptr == 0) - { - *errorptr = ERR18; - goto PCRE_ERROR_RETURN; - } - continue; - - /* Non-referencing groups and lookaheads just move the pointer on, and - then behave like a non-special bracket, except that they don't increment - the count of extracting brackets. Ditto for the "once only" bracket, - which is in Perl from version 5.005. */ - - case ':': - case '=': - case '!': - case '>': - ptr += 2; - break; - - /* A recursive call to the regex is an extension, to provide the - facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */ - - case 'R': - if (ptr[3] != ')') - { - *errorptr = ERR29; - goto PCRE_ERROR_RETURN; - } - ptr += 3; - length += 1; - break; - - /* Lookbehinds are in Perl from version 5.005 */ - - case '<': - if (ptr[3] == '=' || ptr[3] == '!') - { - ptr += 3; - branch_newextra = 3; - length += 3; /* For the first branch */ - break; - } - *errorptr = ERR24; - goto PCRE_ERROR_RETURN; - - /* Conditionals are in Perl from version 5.005. The bracket must either - be followed by a number (for bracket reference) or by an assertion - group. */ - - case '(': - if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0) - { - ptr += 4; - length += 3; - while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++; - if (*ptr != ')') - { - *errorptr = ERR26; - goto PCRE_ERROR_RETURN; - } - } - else /* An assertion must follow */ - { - ptr++; /* Can treat like ':' as far as spacing is concerned */ - if (ptr[2] != '?' || - (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) - { - ptr += 2; /* To get right offset in message */ - *errorptr = ERR28; - goto PCRE_ERROR_RETURN; - } - } - break; - - /* Else loop checking valid options until ) is met. Anything else is an - error. If we are without any brackets, i.e. at top level, the settings - act as if specified in the options, so massage the options immediately. - This is for backward compatibility with Perl 5.004. */ - - default: - set = unset = 0; - optset = &set; - ptr += 2; - - for (;; ptr++) - { - c = *ptr; - switch (c) - { - case 'i': - *optset |= PCRE_CASELESS; - continue; - - case 'm': - *optset |= PCRE_MULTILINE; - continue; - - case 's': - *optset |= PCRE_DOTALL; - continue; - - case 'x': - *optset |= PCRE_EXTENDED; - continue; - - case 'X': - *optset |= PCRE_EXTRA; - continue; - - case 'U': - *optset |= PCRE_UNGREEDY; - continue; - - case '-': - optset = &unset; - continue; - - /* A termination by ')' indicates an options-setting-only item; - this is global at top level; otherwise nothing is done here and - it is handled during the compiling process on a per-bracket-group - basis. */ - - case ')': - if (brastackptr == 0) - { - options = (options | set) & (~unset); - set = unset = 0; /* To save length */ - } - /* Fall through */ - - /* A termination by ':' indicates the start of a nested group with - the given options set. This is again handled at compile time, but - we must allow for compiled space if any of the ims options are - set. We also have to allow for resetting space at the end of - the group, which is why 4 is added to the length and not just 2. - If there are several changes of options within the same group, this - will lead to an over-estimate on the length, but this shouldn't - matter very much. We also have to allow for resetting options at - the start of any alternations, which we do by setting - branch_newextra to 2. Finally, we record whether the case-dependent - flag ever changes within the regex. This is used by the "required - character" code. */ - - case ':': - if (((set|unset) & PCRE_IMS) != 0) - { - length += 4; - branch_newextra = 2; - if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED; - } - goto END_OPTIONS; - - /* Unrecognized option character */ - - default: - *errorptr = ERR12; - goto PCRE_ERROR_RETURN; - } - } - - /* If we hit a closing bracket, that's it - this is a freestanding - option-setting. We need to ensure that branch_extra is updated if - necessary. The only values branch_newextra can have here are 0 or 2. - If the value is 2, then branch_extra must either be 2 or 5, depending - on whether this is a lookbehind group or not. */ - - END_OPTIONS: - if (c == ')') - { - if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3)) - branch_extra += branch_newextra; - continue; - } - - /* If options were terminated by ':' control comes here. Fall through - to handle the group below. */ - } - } - - /* Extracting brackets must be counted so we can process escapes in a - Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to - need an additional 3 bytes of store per extracting bracket. */ - - else - { - bracount++; - if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3; - } - - /* Save length for computing whole length at end if there's a repeat that - requires duplication of the group. Also save the current value of - branch_extra, and start the new group with the new value. If non-zero, this - will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ - - if (brastackptr >= sizeof(brastack)/sizeof(int)) - { - *errorptr = ERR19; - goto PCRE_ERROR_RETURN; - } - - bralenstack[brastackptr] = branch_extra; - branch_extra = branch_newextra; - - brastack[brastackptr++] = length; - length += bracket_length; - continue; - - /* Handle ket. Look for subsequent max/min; for certain sets of values we - have to replicate this bracket up to that many times. If brastackptr is - 0 this is an unmatched bracket which will generate an error, but take care - not to try to access brastack[-1] when computing the length and restoring - the branch_extra value. */ - - case ')': - length += 3; - { - int minval = 1; - int maxval = 1; - int duplength; - - if (brastackptr > 0) - { - duplength = length - brastack[--brastackptr]; - branch_extra = bralenstack[brastackptr]; - } - else duplength = 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, &compile_block)) - { - ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr, - &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - } - else if (c == '*') { minval = 0; maxval = -1; ptr++; } - else if (c == '+') { maxval = -1; ptr++; } - else if (c == '?') { minval = 0; ptr++; } - - /* If the minimum is zero, we have to allow for an OP_BRAZERO before the - group, and if the maximum is greater than zero, we have to replicate - maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting - bracket set - hence the 7. */ - - if (minval == 0) - { - length++; - if (maxval > 0) length += (maxval - 1) * (duplength + 7); - } - - /* When the minimum is greater than zero, 1 we have to replicate up to - minval-1 times, with no additions required in the copies. Then, if - there is a limited maximum we have to replicate up to maxval-1 times - allowing for a BRAZERO item before each optional copy and nesting - brackets for all but one of the optional copies. */ - - else - { - length += (minval - 1) * duplength; - if (maxval > minval) /* Need this test as maxval=-1 means no limit */ - length += (maxval - minval) * (duplength + 7) - 6; - } - } - continue; - - /* Non-special character. For a run of such characters the length required - is the number of characters + 2, except that the maximum run length is 255. - We won't get a skipped space or a non-data escape or the start of a # - comment as the first character, so the length can't be zero. */ - - NORMAL_CHAR: - default: - length += 2; - runlength = 0; - do - { - if ((options & PCRE_EXTENDED) != 0) - { - if ((compile_block.ctypes[c] & ctype_space) != 0) continue; - if (c == '#') - { - /* The space before the ; is to avoid a warning on a silly compiler - on the Macintosh. */ - while ((c = *(++ptr)) != 0 && c != '\n') ; - continue; - } - } - - /* Backslash may introduce a data char or a metacharacter; stop the - string before the latter. */ - - if (c == '\\') - { - const uschar *saveptr = ptr; - c = check_escape(&ptr, errorptr, bracount, options, FALSE, - &compile_block); - if (*errorptr != NULL) goto PCRE_ERROR_RETURN; - if (c < 0) { ptr = saveptr; break; } + if (errorptr == NULL) + return NULL; + *errorptr = NULL; + + if (erroroffset == NULL) { + *errorptr = ERR16; + return NULL; + } + *erroroffset = 0; + + if ((options & ~PUBLIC_OPTIONS) != 0) { + *errorptr = ERR17; + return NULL; + } + + if (tables == NULL) + tables = pcre_default_tables; + compile_block.lcc = tables + lcc_offset; + compile_block.fcc = tables + fcc_offset; + compile_block.cbits = tables + cbits_offset; + compile_block.ctypes = tables + ctypes_offset; + + ptr = (const uschar *)(pattern - 1); + while ((c = *(++ptr)) != 0) { + int min, max; + int class_charcount; + int bracket_length; + + if ((options & PCRE_EXTENDED) != 0) { + if ((compile_block.ctypes[c] & ctype_space) != 0) + continue; + if (c == '#') { + while ((c = *(++ptr)) != 0 && c != '\n') ; + continue; + } + } + + switch (c) { + case '\\': + { + const uschar *save_ptr = ptr; + c = + check_escape(&ptr, errorptr, bracount, options, FALSE, + &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if (c >= 0) { + ptr = save_ptr; + c = '\\'; + goto NORMAL_CHAR; + } + } + length++; + + if (c <= -ESC_REF) { + int refnum = -c - ESC_REF; + if (refnum > top_backref) + top_backref = refnum; + length += 2; + if (ptr[1] == '{' + && is_counted_repeat(ptr + 2, &compile_block)) { + ptr = + read_repeat_counts(ptr + 2, &min, &max, errorptr, + &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + else + length += 5; + if (ptr[1] == '?') + ptr++; + } + } + continue; + + case '^': + case '.': + case '$': + case '*': + case '+': + case '?': + length++; + continue; + + case '{': + if (!is_counted_repeat(ptr + 1, &compile_block)) + goto NORMAL_CHAR; + ptr = + read_repeat_counts(ptr + 1, &min, &max, errorptr, + &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + else { + length--; + if (min == 1) + length++; + else if (min > 0) + length += 4; + if (max > 0) + length += 4; + else + length += 2; + } + if (ptr[1] == '?') + ptr++; + continue; + + case '|': + length += 3 + branch_extra; + continue; + + case '[': + class_charcount = 0; + if (*(++ptr) == '^') + ptr++; + do { + if (*ptr == '\\') { + int ch = + check_escape(&ptr, errorptr, bracount, options, + TRUE, + &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if (-ch == ESC_b) + class_charcount++; + else + class_charcount = 10; + } + else + class_charcount++; + ptr++; + } + while (*ptr != 0 && *ptr != ']'); + + if (class_charcount == 1) + length += 3; + else { + length += 33; + + if (*ptr != 0 && ptr[1] == '{' + && is_counted_repeat(ptr + 2, &compile_block)) { + ptr = + read_repeat_counts(ptr + 2, &min, &max, errorptr, + &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if ((min == 0 && (max == 1 || max == -1)) || + (min == 1 && max == -1)) + length++; + else + length += 5; + if (ptr[1] == '?') + ptr++; + } + } + continue; + + case '(': + branch_newextra = 0; + bracket_length = 3; + + if (ptr[1] == '?') { + int set, unset; + int *optset; + + switch (c = ptr[2]) { + case '#': + ptr += 3; + while (*ptr != 0 && *ptr != ')') + ptr++; + if (*ptr == 0) { + *errorptr = ERR18; + goto PCRE_ERROR_RETURN; + } + continue; + + case ':': + case '=': + case '!': + case '>': + ptr += 2; + break; + + case 'R': + if (ptr[3] != ')') { + *errorptr = ERR29; + goto PCRE_ERROR_RETURN; + } + ptr += 3; + length += 1; + break; + + case '<': + if (ptr[3] == '=' || ptr[3] == '!') { + ptr += 3; + branch_newextra = 3; + length += 3; + break; + } + *errorptr = ERR24; + goto PCRE_ERROR_RETURN; + + case '(': + if ((compile_block.ctypes[ptr[3]] & ctype_digit) + != 0) { + ptr += 4; + length += 3; + while ( + (compile_block. + ctypes[*ptr] & ctype_digit) != 0) + ptr++; + if (*ptr != ')') { + *errorptr = ERR26; + goto PCRE_ERROR_RETURN; + } + } + else { + ptr++; + if (ptr[2] != '?' || + (ptr[3] != '=' && ptr[3] != '!' + && ptr[3] != '<')) { + ptr += 2; + *errorptr = ERR28; + goto PCRE_ERROR_RETURN; + } + } + break; + + default: + set = unset = 0; + optset = &set; + ptr += 2; + + for (;; ptr++) { + c = *ptr; + switch (c) { + case 'i': + *optset |= PCRE_CASELESS; + continue; + + case 'm': + *optset |= PCRE_MULTILINE; + continue; + + case 's': + *optset |= PCRE_DOTALL; + continue; + + case 'x': + *optset |= PCRE_EXTENDED; + continue; + + case 'X': + *optset |= PCRE_EXTRA; + continue; + + case 'U': + *optset |= PCRE_UNGREEDY; + continue; + + case '-': + optset = &unset; + continue; + + case ')': + if (brastackptr == 0) { + options = + (options | set) & (~unset); + set = unset = 0; + } + + case ':': + if (((set | unset) & PCRE_IMS) != 0) { + length += 4; + branch_newextra = 2; + if ( + ((set | unset) & + PCRE_CASELESS) != 0) + options |= PCRE_ICHANGED; + } + goto END_OPTIONS; + + default: + *errorptr = ERR12; + goto PCRE_ERROR_RETURN; + } + } + + END_OPTIONS: + if (c == ')') { + if (branch_newextra == 2 + && (branch_extra == 0 + || branch_extra == 3)) branch_extra += + branch_newextra; + continue; + } + + } + } + + else { + bracount++; + if (bracount > EXTRACT_BASIC_MAX) + bracket_length += 3; + } + + if (brastackptr >= sizeof (brastack) / sizeof (int)) { + *errorptr = ERR19; + goto PCRE_ERROR_RETURN; + } + + bralenstack[brastackptr] = branch_extra; + branch_extra = branch_newextra; + + brastack[brastackptr++] = length; + length += bracket_length; + continue; + + case ')': + length += 3; + { + int minval = 1; + int maxval = 1; + int duplength; + + if (brastackptr > 0) { + duplength = length - brastack[--brastackptr]; + branch_extra = bralenstack[brastackptr]; + } + else + duplength = 0; + + if ((c = ptr[1]) == '{' + && is_counted_repeat(ptr + 2, &compile_block)) { + ptr = + read_repeat_counts(ptr + 2, &minval, &maxval, + errorptr, &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + } + else if (c == '*') { + minval = 0; + maxval = -1; + ptr++; + } + else if (c == '+') { + maxval = -1; + ptr++; + } + else if (c == '?') { + minval = 0; + ptr++; + } + + if (minval == 0) { + length++; + if (maxval > 0) + length += (maxval - 1) * (duplength + 7); + } + + else { + length += (minval - 1) * duplength; + if (maxval > minval) + length += (maxval - minval) * (duplength + 7) - 6; + } + } + continue; + + NORMAL_CHAR: + default: + length += 2; + runlength = 0; + do { + if ((options & PCRE_EXTENDED) != 0) { + if ((compile_block.ctypes[c] & ctype_space) != 0) + continue; + if (c == '#') { + while ((c = *(++ptr)) != 0 && c != '\n') ; + continue; + } + } + + if (c == '\\') { + const uschar *saveptr = ptr; + c = + check_escape(&ptr, errorptr, bracount, options, + FALSE, &compile_block); + if (*errorptr != NULL) + goto PCRE_ERROR_RETURN; + if (c < 0) { + ptr = saveptr; + break; + } #ifdef STR_PCRE_SUPPORT_UTF8 - if (c > 127 && (options & PCRE_UTF8) != 0) - { - int i; - for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) - if (c <= utf8_table1[i]) break; - runlength += i; - } + if (c > 127 && (options & PCRE_UTF8) != 0) { + int i; + for (i = 0; + i < sizeof (utf8_table1) / sizeof (int); i++) + if (c <= utf8_table1[i]) + break; + runlength += i; + } #endif - } - - /* Ordinary character or single-char escape */ - - runlength++; - } + } - /* This "while" is the end of the "do" above. */ + runlength++; + } - while (runlength < MAXLIT && - (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0); + while (runlength < MAXLIT && + (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == + 0); + + ptr--; + length += runlength; + continue; + } + } + + length += 4; + + if (length > 65539) { + *errorptr = ERR20; + return NULL; + } + + size = length + offsetof(pcre_st, code[0]); + re = (pcre_st *) (pcre_malloc) (size); + + if (re == NULL) { + *errorptr = ERR21; + return NULL; + } + + re->magic_number = MAGIC_NUMBER; + re->size = size; + re->options = options; + re->tables = tables; + + ptr = (const uschar *)pattern; + code = re->code; + *code = OP_BRA; + bracount = 0; + (void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, 0, + &reqchar, &countlits, &compile_block); + re->top_bracket = bracount; + re->top_backref = top_backref; + + if (*errorptr == NULL && *ptr != 0) + *errorptr = ERR22; + + *code++ = OP_END; + if (code - re->code > length) + *errorptr = ERR23; + + if (top_backref > re->top_bracket) + *errorptr = ERR15; + + if (*errorptr != NULL) { + (pcre_free) (re); + PCRE_ERROR_RETURN: + *erroroffset = ptr - (const uschar *)pattern; + return NULL; + } + + if ((options & PCRE_ANCHORED) == 0) { + int temp_options = options; + if (is_anchored(re->code, &temp_options)) + re->options |= PCRE_ANCHORED; + else { + int ch = find_firstchar(re->code, &temp_options); + if (ch >= 0) { + re->first_char = ch; + re->options |= PCRE_FIRSTSET; + } + else if (is_startline(re->code)) + re->options |= PCRE_STARTLINE; + } + } + + if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0)) { + re->req_char = reqchar; + re->options |= PCRE_REQCHSET; + } - ptr--; - length += runlength; - continue; - } - } - -length += 4; /* For final KET and END */ - -if (length > 65539) - { - *errorptr = ERR20; - return NULL; - } - -/* Compute the size of data block needed and get it, either from malloc or -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[0]); -re = (real_pcre *)(pcre_malloc)(size); - -if (re == NULL) - { - *errorptr = ERR21; - return NULL; - } - -/* Put in the magic number, and save the size, options, and table pointer */ - -re->magic_number = MAGIC_NUMBER; -re->size = size; -re->options = options; -re->tables = tables; - -/* Set up a starting, non-extracting bracket, then compile the expression. On -error, *errorptr will be set non-NULL, so we don't need to look at the result -of the function here. */ - -ptr = (const uschar *)pattern; -code = re->code; -*code = OP_BRA; -bracount = 0; -(void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, 0, - &reqchar, &countlits, &compile_block); -re->top_bracket = bracount; -re->top_backref = top_backref; - -/* If not reached end of pattern on success, there's an excess bracket. */ - -if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22; - -/* Fill in the terminating state and check for disastrous overflow, but -if debugging, leave the test till after things are printed out. */ - -*code++ = OP_END; -if (code - re->code > length) *errorptr = ERR23; - -/* Give an error if there's back reference to a non-existent capturing -subpattern. */ - -if (top_backref > re->top_bracket) *errorptr = ERR15; - -/* Failed to compile */ - -if (*errorptr != NULL) - { - (pcre_free)(re); - PCRE_ERROR_RETURN: - *erroroffset = ptr - (const uschar *)pattern; - return NULL; - } - -/* If the anchored option was not passed, set flag if we can determine that the -pattern is anchored by virtue of ^ characters or \A or anything else (such as -starting with .* when DOTALL is set). - -Otherwise, see if we can determine what the first character has to be, because -that speeds up unanchored matches no end. If not, see if we can set the -PCRE_STARTLINE flag. This is helpful for multiline matches when all branches -start with ^. and also when all branches start with .* for non-DOTALL matches. -*/ - -if ((options & PCRE_ANCHORED) == 0) - { - int temp_options = options; - if (is_anchored(re->code, &temp_options)) - re->options |= PCRE_ANCHORED; - else - { - int ch = find_firstchar(re->code, &temp_options); - if (ch >= 0) - { - re->first_char = ch; - re->options |= PCRE_FIRSTSET; - } - else if (is_startline(re->code)) - re->options |= PCRE_STARTLINE; - } - } - -/* Save the last required character if there are at least two literal -characters on all paths, or if there is no first character setting. */ - -if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0)) - { - re->req_char = reqchar; - re->options |= PCRE_REQCHSET; - } - -/* Print out the compiled data for debugging */ - -return (pcre *)re; + return (pcre *) re; } -/************************************************* -* Match a back-reference * -*************************************************/ - -/* If a back reference hasn't been set, the length that is passed is greater -than the number of characters left in the string, so the match fails. - -Arguments: - offset index into the offset vector - eptr points into the subject - length length to be matched - md points to match data block - ims the ims flags - -Returns: TRUE if matched -*/ - static BOOL -match_ref(int offset, register const uschar *eptr, int length, match_data *md, - unsigned long int ims) +match_ref(int offset, register const uschar * eptr, int length, + match_data * md, unsigned long int ims) { -const uschar *p = md->start_subject + md->offset_vector[offset]; - -/* Always fail if not enough characters left */ + const uschar *p = md->start_subject + md->offset_vector[offset]; -if (length > md->end_subject - eptr) return FALSE; + if (length > md->end_subject - eptr) + return FALSE; -/* Separate the caselesss case for speed */ + if ((ims & PCRE_CASELESS) != 0) { + while (length-- > 0) + if (md->lcc[*p++] != md->lcc[*eptr++]) + return FALSE; + } + else { + while (length-- > 0) + if (*p++ != *eptr++) + return FALSE; + } -if ((ims & PCRE_CASELESS) != 0) - { - while (length-- > 0) - if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; - } -else - { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } - -return TRUE; + return TRUE; } -/************************************************* -* Match from current position * -*************************************************/ - -/* On entry ecode points to the first opcode, and eptr to the first character -in the subject string, while eptrb holds the value of eptr at the start of the -last bracketed group - used for breaking infinite loops matching zero-length -strings. - -Arguments: - eptr pointer in subject - ecode position in code - offset_top current top pointer - md pointer to "static" info for the match - ims current /i, /m, and /s options - eptrb pointer to chain of blocks containing eptr at start of - brackets - for testing for empty matches - flags can contain - match_condassert - this is an assertion condition - match_isgroup - this is the start of a bracketed group - -Returns: TRUE if matched -*/ - static BOOL -match(register const uschar *eptr, register const uschar *ecode, - int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, - int flags) +match(register const uschar * eptr, register const uschar * ecode, + int offset_top, match_data * md, unsigned long int ims, + eptrblock * eptrb, int flags) { -unsigned long int original_ims = ims; /* Save for resetting on ')' */ -eptrblock newptrb; - -/* At the start of a bracketed group, add the current subject pointer to the -stack of such pointers, to be re-instated at the end of the group when we hit -the closing ket. When match() is called in other circumstances, we don't add to -the stack. */ - -if ((flags & match_isgroup) != 0) - { - newptrb.prev = eptrb; - newptrb.saved_eptr = eptr; - eptrb = &newptrb; - } - -/* Now start processing the operations. */ - -for (;;) - { - int op = (int)*ecode; - int min, max, ctype; - register int i; - register int c; - BOOL minimize = FALSE; - - /* Opening capturing bracket. If there is space in the offset vector, save - the current subject position in the working slot at the top of the vector. We - mustn't change the current values of the data slot, because they may be set - from a previous iteration of this group, and be referred to by a reference - inside the group. - - If the bracket fails to match, we need to restore this value and also the - values of the final offsets, in case they were set by a previous iteration of - the same bracket. - - If there isn't enough space in the offset vector, treat this as if it were a - non-capturing bracket. Don't worry about setting the flag for the error case - here; that is handled in the code for KET. */ - - if (op > OP_BRA) - { - int offset; - int number = op - OP_BRA; - - /* For extended extraction brackets (large number), we have to fish out the - number from a dummy opcode at the start. */ - - if (number > EXTRACT_BASIC_MAX) number = (ecode[4] << 8) | ecode[5]; - offset = number << 1; - - if (offset < md->offset_max) - { - int save_offset1 = md->offset_vector[offset]; - int save_offset2 = md->offset_vector[offset+1]; - int save_offset3 = md->offset_vector[md->offset_end - number]; - - md->offset_vector[md->offset_end - number] = eptr - md->start_subject; - - do - { - if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - ecode += (ecode[1] << 8) + ecode[2]; - } - while (*ecode == OP_ALT); - - md->offset_vector[offset] = save_offset1; - md->offset_vector[offset+1] = save_offset2; - md->offset_vector[md->offset_end - number] = save_offset3; + unsigned long int original_ims = ims; + eptrblock newptrb; - return FALSE; - } + if ((flags & match_isgroup) != 0) { + newptrb.prev = eptrb; + newptrb.saved_eptr = eptr; + eptrb = &newptrb; + } + + for (;;) { + int op = (int)*ecode; + int min, max, ctype; + register int i; + register int c; + BOOL minimize = FALSE; + + if (op > OP_BRA) { + int offset; + int number = op - OP_BRA; + + if (number > EXTRACT_BASIC_MAX) + number = (ecode[4] << 8) | ecode[5]; + offset = number << 1; + + if (offset < md->offset_max) { + int save_offset1 = md->offset_vector[offset]; + int save_offset2 = md->offset_vector[offset + 1]; + int save_offset3 = md->offset_vector[md->offset_end - number]; + + md->offset_vector[md->offset_end - number] = + eptr - md->start_subject; + + do { + if (match + (eptr, ecode + 3, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + ecode += (ecode[1] << 8) + ecode[2]; + } + while (*ecode == OP_ALT); + + md->offset_vector[offset] = save_offset1; + md->offset_vector[offset + 1] = save_offset2; + md->offset_vector[md->offset_end - number] = save_offset3; + + return FALSE; + } + + else + op = OP_BRA; + } + + switch (op) { + case OP_BRA: + + do { + if (match + (eptr, ecode + 3, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + ecode += (ecode[1] << 8) + ecode[2]; + } + while (*ecode == OP_ALT); + + return FALSE; + + case OP_COND: + if (ecode[3] == OP_CREF) { + int offset = (ecode[4] << 9) | (ecode[5] << 1); + return match(eptr, + ecode + + ((offset + < offset_top + && md->offset_vector[offset] >= + 0) ? 6 : 3 + (ecode[1] << 8) + ecode[2]), + offset_top, md, ims, eptrb, match_isgroup); + } + + else { + if (match(eptr, ecode + 3, offset_top, md, ims, NULL, + match_condassert | match_isgroup)) { + ecode += 3 + (ecode[4] << 8) + ecode[5]; + while (*ecode == OP_ALT) + ecode += (ecode[1] << 8) + ecode[2]; + } + else + ecode += (ecode[1] << 8) + ecode[2]; + return match(eptr, ecode + 3, offset_top, md, ims, eptrb, + match_isgroup); + } + + case OP_CREF: + case OP_BRANUMBER: + ecode += 3; + break; + + case OP_END: + if (md->notempty && eptr == md->start_match) + return FALSE; + md->end_match_ptr = eptr; + md->end_offset_top = offset_top; + return TRUE; + + case OP_OPT: + ims = ecode[1]; + ecode += 2; + + break; + + case OP_ASSERT: + case OP_ASSERTBACK: + do { + if (match + (eptr, ecode + 3, offset_top, md, ims, NULL, + match_isgroup)) break; + ecode += (ecode[1] << 8) + ecode[2]; + } + while (*ecode == OP_ALT); + if (*ecode == OP_KET) + return FALSE; + + if ((flags & match_condassert) != 0) + return TRUE; + + do + ecode += (ecode[1] << 8) + ecode[2]; + while (*ecode == OP_ALT); + ecode += 3; + offset_top = md->end_offset_top; + continue; + + case OP_ASSERT_NOT: + case OP_ASSERTBACK_NOT: + do { + if (match + (eptr, ecode + 3, offset_top, md, ims, NULL, + match_isgroup)) return FALSE; + ecode += (ecode[1] << 8) + ecode[2]; + } + while (*ecode == OP_ALT); - /* Insufficient room for saving captured contents */ + if ((flags & match_condassert) != 0) + return TRUE; - else op = OP_BRA; - } - - /* Other types of node can be handled by a switch */ + ecode += 3; + continue; - switch(op) - { - case OP_BRA: /* Non-capturing bracket: optimized */ - - do - { - if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - ecode += (ecode[1] << 8) + ecode[2]; - } - while (*ecode == OP_ALT); - - return FALSE; - - /* Conditional group: compilation checked that there are no more than - two branches. If the condition is false, skipping the first branch takes us - past the end if there is only one branch, but that's OK because that is - exactly what going to the ket would do. */ - - case OP_COND: - if (ecode[3] == OP_CREF) /* Condition is extraction test */ - { - int offset = (ecode[4] << 9) | (ecode[5] << 1); /* Doubled ref number */ - return match(eptr, - ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)? - 6 : 3 + (ecode[1] << 8) + ecode[2]), - offset_top, md, ims, eptrb, match_isgroup); - } - - /* The condition is an assertion. Call match() to evaluate it - setting - the final argument TRUE causes it to stop at the end of an assertion. */ - - else - { - if (match(eptr, ecode+3, offset_top, md, ims, NULL, - match_condassert | match_isgroup)) - { - ecode += 3 + (ecode[4] << 8) + ecode[5]; - while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2]; - } - else ecode += (ecode[1] << 8) + ecode[2]; - return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup); - } - /* Control never reaches here */ - - /* Skip over conditional reference or large extraction number data if - encountered. */ - - case OP_CREF: - case OP_BRANUMBER: - ecode += 3; - break; - - case OP_END: - if (md->notempty && eptr == md->start_match) return FALSE; - md->end_match_ptr = eptr; /* Record where we ended */ - md->end_offset_top = offset_top; /* and how many extracts were taken */ - return TRUE; - - /* Change option settings */ - - case OP_OPT: - ims = ecode[1]; - ecode += 2; - - break; - - /* Assertion brackets. Check the alternative branches in turn - the - matching won't pass the KET for an assertion. If any one branch matches, - the assertion is true. Lookbehind assertions have an OP_REVERSE item at the - start of each branch to move the current point backwards, so the code at - this level is identical to the lookahead case. */ - - case OP_ASSERT: - case OP_ASSERTBACK: - do - { - if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break; - ecode += (ecode[1] << 8) + ecode[2]; - } - while (*ecode == OP_ALT); - if (*ecode == OP_KET) return FALSE; - - /* If checking an assertion for a condition, return TRUE. */ - - if ((flags & match_condassert) != 0) return TRUE; - - /* Continue from after the assertion, updating the offsets high water - mark, since extracts may have been taken during the assertion. */ - - do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); - ecode += 3; - offset_top = md->end_offset_top; - continue; - - /* Negative assertion: all branches must fail to match */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK_NOT: - do - { - if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) - return FALSE; - ecode += (ecode[1] << 8) + ecode[2]; - } - while (*ecode == OP_ALT); - - if ((flags & match_condassert) != 0) return TRUE; - - ecode += 3; - continue; - - /* Move the subject pointer back. This occurs only at the start of - each branch of a lookbehind assertion. If we are too close to the start to - move back, this match function fails. When working with UTF-8 we move - back a number of characters, not bytes. */ - - case OP_REVERSE: + case OP_REVERSE: #ifdef STR_PCRE_SUPPORT_UTF8 - c = (ecode[1] << 8) + ecode[2]; - for (i = 0; i < c; i++) - { - eptr--; - BACKCHAR(eptr) - } + c = (ecode[1] << 8) + ecode[2]; + for (i = 0; i < c; i++) { + eptr--; + BACKCHAR(eptr) + } #else - eptr -= (ecode[1] << 8) + ecode[2]; + eptr -= (ecode[1] << 8) + ecode[2]; #endif - if (eptr < md->start_subject) return FALSE; - ecode += 3; - break; - - /* Recursion matches the current regex, nested. If there are any capturing - brackets started but not finished, we have to save their starting points - and reinstate them after the recursion. However, we don't know how many - such there are (offset_top records the completed total) so we just have - to save all the potential data. There may be up to 99 such values, which - is a bit large to put on the stack, but using malloc for small numbers - seems expensive. As a compromise, the stack is used when there are fewer - than 16 values to store; otherwise malloc is used. A problem is what to do - if the malloc fails ... there is no way of returning to the top level with - an error. Save the top 15 values on the stack, and accept that the rest - may be wrong. */ - - case OP_RECURSE: - { - BOOL rc; - int *save; - int stacksave[15]; - - c = md->offset_max; - - if (c < 16) save = stacksave; else - { - save = (int *)(pcre_malloc)((c+1) * sizeof(int)); - if (save == NULL) - { - save = stacksave; - c = 15; - } - } - - for (i = 1; i <= c; i++) - save[i] = md->offset_vector[md->offset_end - i]; - rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb, - match_isgroup); - for (i = 1; i <= c; i++) - md->offset_vector[md->offset_end - i] = save[i]; - if (save != stacksave) (pcre_free)(save); - if (!rc) return FALSE; - - /* In case the recursion has set more capturing values, save the final - number, then move along the subject till after the recursive match, - and advance one byte in the pattern code. */ - - offset_top = md->end_offset_top; - eptr = md->end_match_ptr; - ecode++; - } - break; - - /* "Once" brackets are like assertion brackets except that after a match, - the point in the subject string is not moved back. Thus there can never be - a move back into the brackets. Check the alternative branches in turn - the - matching won't pass the KET for this kind of subpattern. If any one branch - matches, we carry on as at the end of a normal bracket, leaving the subject - pointer. */ - - case OP_ONCE: - { - const uschar *prev = ecode; - const uschar *saved_eptr = eptr; - - do - { - if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) - break; - ecode += (ecode[1] << 8) + ecode[2]; - } - while (*ecode == OP_ALT); - - /* If hit the end of the group (which could be repeated), fail */ - - if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE; - - /* Continue as from after the assertion, updating the offsets high water - mark, since extracts may have been taken. */ - - do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); - - offset_top = md->end_offset_top; - eptr = md->end_match_ptr; - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*ecode == OP_KET || eptr == saved_eptr) - { - ecode += 3; - break; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. We need to reset any options - that changed within the bracket before re-running it, so check the next - opcode. */ - - if (ecode[3] == OP_OPT) - { - ims = (ims & ~PCRE_IMS) | ecode[4]; - - } - - if (*ecode == OP_KETRMIN) - { - if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || - match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - } - else /* OP_KETRMAX */ - { - if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || - match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; - } - } - return FALSE; - - /* An alternation is the end of a branch; scan along to find the end of the - bracketed group and go to there. */ - - case OP_ALT: - do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); - break; - - /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating - that it may occur zero times. It may repeat infinitely, or not at all - - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper - repeat limits are compiled as a number of copies, with the optional ones - preceded by BRAZERO or BRAMINZERO. */ - - case OP_BRAZERO: - { - const uschar *next = ecode+1; - if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); - ecode = next + 3; - } - break; - - case OP_BRAMINZERO: - { - const uschar *next = ecode+1; - do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); - if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - ecode++; - } - break; - - case OP_KET: - case OP_KETRMIN: - case OP_KETRMAX: - { - const uschar *prev = ecode - (ecode[1] << 8) - ecode[2]; - const uschar *saved_eptr = eptrb->saved_eptr; - - eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */ - - if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || - *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || - *prev == OP_ONCE) - { - md->end_match_ptr = eptr; /* For ONCE */ - md->end_offset_top = offset_top; - return TRUE; - } - - /* In all other cases except a conditional group we have to check the - group number back at the start and if necessary complete handling an - extraction by setting the offsets and bumping the high water mark. */ - - if (*prev != OP_COND) - { - int offset; - int number = *prev - OP_BRA; - - /* For extended extraction brackets (large number), we have to fish out - the number from a dummy opcode at the start. */ - - if (number > EXTRACT_BASIC_MAX) number = (prev[4] << 8) | prev[5]; - offset = number << 1; - - if (number > 0) - { - if (offset >= md->offset_max) md->offset_overflow = TRUE; else - { - md->offset_vector[offset] = - md->offset_vector[md->offset_end - number]; - md->offset_vector[offset+1] = eptr - md->start_subject; - if (offset_top <= offset) offset_top = offset + 2; - } - } - } - - /* Reset the value of the ims flags, in case they got changed during - the group. */ - - ims = original_ims; - - /* For a non-repeating ket, just continue at this level. This also - happens for a repeating ket if no characters were matched in the group. - This is the forcible breaking of infinite loops as implemented in Perl - 5.005. If there is an options reset, it will get obeyed in the normal - course of events. */ - - if (*ecode == OP_KET || eptr == saved_eptr) - { - ecode += 3; - break; - } - - /* The repeating kets try the rest of the pattern or restart from the - preceding bracket, in the appropriate order. */ - - if (*ecode == OP_KETRMIN) - { - if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || - match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) - return TRUE; - } - else /* OP_KETRMAX */ - { - if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || - match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; - } - } - return FALSE; - - /* Start of subject unless notbol, or after internal newline if multiline */ - - case OP_CIRC: - if (md->notbol && eptr == md->start_subject) return FALSE; - if ((ims & PCRE_MULTILINE) != 0) - { - if (eptr != md->start_subject && eptr[-1] != '\n') return FALSE; - ecode++; - break; - } - /* ... else fall through */ - - /* Start of subject assertion */ - - case OP_SOD: - if (eptr != md->start_subject) return FALSE; - ecode++; - break; - - /* Assert before internal newline if multiline, or before a terminating - newline unless endonly is set, else end of subject unless noteol is set. */ - - case OP_DOLL: - if ((ims & PCRE_MULTILINE) != 0) - { - if (eptr < md->end_subject) { if (*eptr != '\n') return FALSE; } - else { if (md->noteol) return FALSE; } - ecode++; - break; - } - else - { - if (md->noteol) return FALSE; - if (!md->endonly) - { - if (eptr < md->end_subject - 1 || - (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE; - - ecode++; - break; - } - } - /* ... else fall through */ - - case OP_EOD: - if (eptr < md->end_subject) return FALSE; - ecode++; - break; - - case OP_EODN: - if (eptr < md->end_subject - 1 || - (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE; - ecode++; - break; - - /* Word boundary assertions */ - - case OP_NOT_WORD_BOUNDARY: - case OP_WORD_BOUNDARY: - { - BOOL prev_is_word = (eptr != md->start_subject) && - ((md->ctypes[eptr[-1]] & ctype_word) != 0); - BOOL cur_is_word = (eptr < md->end_subject) && - ((md->ctypes[*eptr] & ctype_word) != 0); - if ((*ecode++ == OP_WORD_BOUNDARY)? - cur_is_word == prev_is_word : cur_is_word != prev_is_word) - return FALSE; - } - break; - - /* Match a single character type; inline for speed */ - - case OP_ANY: - if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == '\n') - return FALSE; - if (eptr++ >= md->end_subject) return FALSE; + if (eptr < md->start_subject) + return FALSE; + ecode += 3; + break; + + case OP_RECURSE: + { + BOOL rc; + int *save; + int stacksave[15]; + + c = md->offset_max; + + if (c < 16) + save = stacksave; + else { + save = (int *)(pcre_malloc) ((c + 1) * sizeof (int)); + if (save == NULL) { + save = stacksave; + c = 15; + } + } + + for (i = 1; i <= c; i++) + save[i] = md->offset_vector[md->offset_end - i]; + rc = + match(eptr, md->start_pattern, offset_top, md, ims, + eptrb, match_isgroup); + for (i = 1; i <= c; i++) + md->offset_vector[md->offset_end - i] = save[i]; + if (save != stacksave) + (pcre_free) (save); + if (!rc) + return FALSE; + + offset_top = md->end_offset_top; + eptr = md->end_match_ptr; + ecode++; + } + break; + + case OP_ONCE: + { + const uschar *prev = ecode; + const uschar *saved_eptr = eptr; + + do { + if (match + (eptr, ecode + 3, offset_top, md, ims, eptrb, + match_isgroup)) break; + ecode += (ecode[1] << 8) + ecode[2]; + } + while (*ecode == OP_ALT); + + if (*ecode != OP_ONCE && *ecode != OP_ALT) + return FALSE; + + do + ecode += (ecode[1] << 8) + ecode[2]; + while (*ecode == OP_ALT); + + offset_top = md->end_offset_top; + eptr = md->end_match_ptr; + + if (*ecode == OP_KET || eptr == saved_eptr) { + ecode += 3; + break; + } + + if (ecode[3] == OP_OPT) { + ims = (ims & ~PCRE_IMS) | ecode[4]; + + } + + if (*ecode == OP_KETRMIN) { + if (match + (eptr, ecode + 3, offset_top, md, ims, eptrb, 0) + || match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + } + else { + if (match + (eptr, prev, offset_top, md, ims, eptrb, + match_isgroup) + || match(eptr, ecode + 3, offset_top, md, ims, + eptrb, 0)) + return TRUE; + } + } + return FALSE; + + case OP_ALT: + do + ecode += (ecode[1] << 8) + ecode[2]; + while (*ecode == OP_ALT); + break; + + case OP_BRAZERO: + { + const uschar *next = ecode + 1; + if (match + (eptr, next, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + do + next += (next[1] << 8) + next[2]; + while (*next == OP_ALT); + ecode = next + 3; + } + break; + + case OP_BRAMINZERO: + { + const uschar *next = ecode + 1; + do + next += (next[1] << 8) + next[2]; + while (*next == OP_ALT); + if (match + (eptr, next + 3, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + ecode++; + } + break; + + case OP_KET: + case OP_KETRMIN: + case OP_KETRMAX: + { + const uschar *prev = ecode - (ecode[1] << 8) - ecode[2]; + const uschar *saved_eptr = eptrb->saved_eptr; + + eptrb = eptrb->prev; + + if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || + *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT + || *prev == OP_ONCE) { + md->end_match_ptr = eptr; + md->end_offset_top = offset_top; + return TRUE; + } + + if (*prev != OP_COND) { + int offset; + int number = *prev - OP_BRA; + + if (number > EXTRACT_BASIC_MAX) + number = (prev[4] << 8) | prev[5]; + offset = number << 1; + + if (number > 0) { + if (offset >= md->offset_max) + md->offset_overflow = TRUE; + else { + md->offset_vector[offset] = + md->offset_vector[md->offset_end - + number]; + md->offset_vector[offset + 1] = + eptr - md->start_subject; + if (offset_top <= offset) + offset_top = offset + 2; + } + } + } + + ims = original_ims; + + if (*ecode == OP_KET || eptr == saved_eptr) { + ecode += 3; + break; + } + + if (*ecode == OP_KETRMIN) { + if (match + (eptr, ecode + 3, offset_top, md, ims, eptrb, 0) + || match(eptr, prev, offset_top, md, ims, eptrb, + match_isgroup)) return TRUE; + } + else { + if (match + (eptr, prev, offset_top, md, ims, eptrb, + match_isgroup) + || match(eptr, ecode + 3, offset_top, md, ims, + eptrb, 0)) + return TRUE; + } + } + return FALSE; + + case OP_CIRC: + if (md->notbol && eptr == md->start_subject) + return FALSE; + if ((ims & PCRE_MULTILINE) != 0) { + if (eptr != md->start_subject && eptr[-1] != '\n') + return FALSE; + ecode++; + break; + } + + case OP_SOD: + if (eptr != md->start_subject) + return FALSE; + ecode++; + break; + + case OP_DOLL: + if ((ims & PCRE_MULTILINE) != 0) { + if (eptr < md->end_subject) { + if (*eptr != '\n') + return FALSE; + } + else { + if (md->noteol) + return FALSE; + } + ecode++; + break; + } + else { + if (md->noteol) + return FALSE; + if (!md->endonly) { + if (eptr < md->end_subject - 1 || + (eptr == md->end_subject - 1 && *eptr != '\n')) + return FALSE; + + ecode++; + break; + } + } + case OP_EOD: + if (eptr < md->end_subject) + return FALSE; + ecode++; + break; + + case OP_EODN: + if (eptr < md->end_subject - 1 || + (eptr == md->end_subject - 1 && *eptr != '\n')) + return FALSE; + ecode++; + break; + + case OP_NOT_WORD_BOUNDARY: + case OP_WORD_BOUNDARY: + { + BOOL prev_is_word = (eptr != md->start_subject) && + ((md->ctypes[eptr[-1]] & ctype_word) != 0); + BOOL cur_is_word = (eptr < md->end_subject) && + ((md->ctypes[*eptr] & ctype_word) != 0); + if ((*ecode++ == OP_WORD_BOUNDARY) ? + cur_is_word == prev_is_word : cur_is_word != + prev_is_word) return FALSE; + } + break; + + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject + && *eptr == '\n') + return FALSE; + if (eptr++ >= md->end_subject) + return FALSE; #ifdef STR_PCRE_SUPPORT_UTF8 - if (md->utf8) - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + if (md->utf8) + while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) + eptr++; #endif - ecode++; - break; - - case OP_NOT_DIGIT: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_digit) != 0) - return FALSE; - ecode++; - break; - - case OP_DIGIT: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_digit) == 0) - return FALSE; - ecode++; - break; - - case OP_NOT_WHITESPACE: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_space) != 0) - return FALSE; - ecode++; - break; - - case OP_WHITESPACE: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_space) == 0) - return FALSE; - ecode++; - break; - - case OP_NOT_WORDCHAR: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_word) != 0) - return FALSE; - ecode++; - break; - - case OP_WORDCHAR: - if (eptr >= md->end_subject || - (md->ctypes[*eptr++] & ctype_word) == 0) - return FALSE; - ecode++; - break; - - /* Match a back reference, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. The code is similar - to that for character classes, but repeated for efficiency. Then obey - similar code to character type repeats - written out again for speed. - However, if the referenced string is the empty string, always treat - it as matched, any number of times (otherwise there could be infinite - loops). */ - - case OP_REF: - { - int length; - int offset = (ecode[1] << 9) | (ecode[2] << 1); /* Doubled ref number */ - ecode += 3; /* Advance past item */ - - /* If the reference is unset, set the length to be longer than the amount - of subject left; this ensures that every attempt at a match fails. We - can't just fail here, because of the possibility of quantifiers with zero - minima. */ - - length = (offset >= offset_top || md->offset_vector[offset] < 0)? - md->end_subject - eptr + 1 : - md->offset_vector[offset+1] - md->offset_vector[offset]; - - /* Set up for repetition, or handle the non-repeated case */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = (ecode[1] << 8) + ecode[2]; - max = (ecode[3] << 8) + ecode[4]; - if (max == 0) max = INT_MAX; - ecode += 5; - break; - - default: /* No repeat follows */ - if (!match_ref(offset, eptr, length, md, ims)) return FALSE; - eptr += length; - continue; /* With the main loop */ - } - - /* If the length of the reference is zero, just continue with the - main loop. */ - - if (length == 0) continue; - - /* First, ensure the minimum number of matches are present. We get back - the length of the reference string explicitly rather than passing the - address of eptr, so that eptr can be a register variable. */ - - for (i = 1; i <= min; i++) - { - if (!match_ref(offset, eptr, length, md, ims)) return FALSE; - eptr += length; - } - - /* If min = max, continue at the same level without recursion. - They are not both allowed to be zero. */ - - if (min == max) continue; - - /* If minimizing, keep trying and advancing the pointer */ - - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || !match_ref(offset, eptr, length, md, ims)) - return FALSE; - eptr += length; - } - /* Control never gets here */ - } - - /* If maximizing, find the longest string and work backwards */ - - else - { - const uschar *pp = eptr; - for (i = min; i < max; i++) - { - if (!match_ref(offset, eptr, length, md, ims)) break; - eptr += length; - } - while (eptr >= pp) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - eptr -= length; - } - return FALSE; - } - } - /* Control never gets here */ - - /* Match a character class, possibly repeatedly. Look past the end of the - item to see if there is repeat information following. Then obey similar - code to character type repeats - written out again for speed. */ - - case OP_CLASS: - { - const uschar *data = ecode + 1; /* Save for matching */ - ecode += 33; /* Advance past the item */ - - switch (*ecode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRPLUS: - case OP_CRMINPLUS: - case OP_CRQUERY: - case OP_CRMINQUERY: - c = *ecode++ - OP_CRSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - minimize = (*ecode == OP_CRMINRANGE); - min = (ecode[1] << 8) + ecode[2]; - max = (ecode[3] << 8) + ecode[4]; - if (max == 0) max = INT_MAX; - ecode += 5; - break; - - default: /* No repeat follows */ - min = max = 1; - break; - } - - /* First, ensure the minimum number of matches are present. */ - - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject) return FALSE; - GETCHARINC(c, eptr) /* Get character; increment eptr */ + ecode++; + break; + case OP_NOT_DIGIT: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_digit) != 0) + return FALSE; + ecode++; + break; + + case OP_DIGIT: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_digit) == 0) + return FALSE; + ecode++; + break; + + case OP_NOT_WHITESPACE: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_space) != 0) + return FALSE; + ecode++; + break; + + case OP_WHITESPACE: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_space) == 0) + return FALSE; + ecode++; + break; + + case OP_NOT_WORDCHAR: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_word) != 0) + return FALSE; + ecode++; + break; + + case OP_WORDCHAR: + if (eptr >= md->end_subject || + (md->ctypes[*eptr++] & ctype_word) == 0) + return FALSE; + ecode++; + break; + + case OP_REF: + { + int length; + int offset = (ecode[1] << 9) | (ecode[2] << 1); + ecode += 3; + + length = (offset >= offset_top + || md->offset_vector[offset] < + 0) ? md->end_subject - eptr + + 1 : md->offset_vector[offset + 1] - + md->offset_vector[offset]; + + switch (*ecode) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; + max = rep_max[c]; + if (max == 0) + max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = (ecode[1] << 8) + ecode[2]; + max = (ecode[3] << 8) + ecode[4]; + if (max == 0) + max = INT_MAX; + ecode += 5; + break; + + default: + if (!match_ref(offset, eptr, length, md, ims)) + return FALSE; + eptr += length; + continue; + } + + if (length == 0) + continue; + + for (i = 1; i <= min; i++) { + if (!match_ref(offset, eptr, length, md, ims)) + return FALSE; + eptr += length; + } + + if (min == max) + continue; + + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max + || !match_ref(offset, eptr, length, md, ims)) + return FALSE; + eptr += length; + } + } + + else { + const uschar *pp = eptr; + for (i = min; i < max; i++) { + if (!match_ref(offset, eptr, length, md, ims)) + break; + eptr += length; + } + while (eptr >= pp) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + eptr -= length; + } + return FALSE; + } + } + + case OP_CLASS: + { + const uschar *data = ecode + 1; + ecode += 33; + + switch (*ecode) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRPLUS: + case OP_CRMINPLUS: + case OP_CRQUERY: + case OP_CRMINQUERY: + c = *ecode++ - OP_CRSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; + max = rep_max[c]; + if (max == 0) + max = INT_MAX; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + minimize = (*ecode == OP_CRMINRANGE); + min = (ecode[1] << 8) + ecode[2]; + max = (ecode[3] << 8) + ecode[4]; + if (max == 0) + max = INT_MAX; + ecode += 5; + break; + + default: + min = max = 1; + break; + } + + for (i = 1; i <= min; i++) { + if (eptr >= md->end_subject) + return FALSE; + GETCHARINC(c, eptr) #ifdef STR_PCRE_SUPPORT_UTF8 - /* We do not yet support class members > 255 */ - if (c > 255) return FALSE; + if (c > 255) + return FALSE; #endif - if ((data[c/8] & (1 << (c&7))) != 0) continue; - return FALSE; - } - - /* If max == min we can continue with the main loop without the - need to recurse. */ - - if (min == max) continue; - - /* If minimizing, keep testing the rest of the expression and advancing - the pointer while it matches the class. */ - - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || eptr >= md->end_subject) return FALSE; - GETCHARINC(c, eptr) /* Get character; increment eptr */ - + if ((data[c / 8] & (1 << (c & 7))) != 0) + continue; + return FALSE; + } + + if (min == max) + continue; + + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max || eptr >= md->end_subject) + return FALSE; + GETCHARINC(c, eptr) #ifdef STR_PCRE_SUPPORT_UTF8 - /* We do not yet support class members > 255 */ - if (c > 255) return FALSE; + if (c > 255) + return FALSE; #endif - if ((data[c/8] & (1 << (c&7))) != 0) continue; - return FALSE; - } - /* Control never gets here */ - } - - /* If maximizing, find the longest possible run, then work backwards. */ - - else - { - const uschar *pp = eptr; - int len = 1; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject) break; - GETCHARLEN(c, eptr, len) /* Get character, set length if UTF-8 */ - + if ((data[c / 8] & (1 << (c & 7))) != 0) + continue; + return FALSE; + } + } + + else { + const uschar *pp = eptr; + int len = 1; + for (i = min; i < max; i++) { + if (eptr >= md->end_subject) + break; + GETCHARLEN(c, eptr, len) #ifdef STR_PCRE_SUPPORT_UTF8 - /* We do not yet support class members > 255 */ - if (c > 255) break; + if (c > 255) + break; #endif - if ((data[c/8] & (1 << (c&7))) == 0) break; - eptr += len; - } - - while (eptr >= pp) - { - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; + if ((data[c / 8] & (1 << (c & 7))) == 0) + break; + eptr += len; + } + + while (eptr >= pp) { + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; #ifdef STR_PCRE_SUPPORT_UTF8 - BACKCHAR(eptr) + BACKCHAR(eptr) #endif - } - return FALSE; - } - } - /* Control never gets here */ - - /* Match a run of characters */ - - case OP_CHARS: - { - register int length = ecode[1]; - ecode += 2; - - if (length > md->end_subject - eptr) return FALSE; - if ((ims & PCRE_CASELESS) != 0) - { - while (length-- > 0) - if (md->lcc[*ecode++] != md->lcc[*eptr++]) - return FALSE; - } - else - { - while (length-- > 0) if (*ecode++ != *eptr++) return FALSE; - } - } - break; - - /* Match a single character repeatedly; different opcodes share code. */ - - case OP_EXACT: - min = max = (ecode[1] << 8) + ecode[2]; - ecode += 3; - goto REPEATCHAR; - - case OP_UPTO: - case OP_MINUPTO: - min = 0; - max = (ecode[1] << 8) + ecode[2]; - minimize = *ecode == OP_MINUPTO; - ecode += 3; - goto REPEATCHAR; - - case OP_STAR: - case OP_MINSTAR: - case OP_PLUS: - case OP_MINPLUS: - case OP_QUERY: - case OP_MINQUERY: - c = *ecode++ - OP_STAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATCHAR: - if (min > md->end_subject - eptr) return FALSE; - c = *ecode++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - if ((ims & PCRE_CASELESS) != 0) - { - c = md->lcc[c]; - for (i = 1; i <= min; i++) - if (c != md->lcc[*eptr++]) return FALSE; - if (min == max) continue; - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || eptr >= md->end_subject || - c != md->lcc[*eptr++]) - return FALSE; - } - /* Control never gets here */ - } - else - { - const uschar *pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || c != md->lcc[*eptr]) break; - eptr++; - } - while (eptr >= pp) - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - return FALSE; - } - /* Control never gets here */ - } - - /* Caseful comparisons */ - - else - { - for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE; - if (min == max) continue; - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE; - } - /* Control never gets here */ - } - else - { - const uschar *pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || c != *eptr) break; - eptr++; - } - while (eptr >= pp) - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - return FALSE; - } - } - /* Control never gets here */ - - /* Match a negated single character */ - - case OP_NOT: - if (eptr >= md->end_subject) return FALSE; - ecode++; - if ((ims & PCRE_CASELESS) != 0) - { - if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE; - } - else - { - if (*ecode++ == *eptr++) return FALSE; - } - break; - - /* Match a negated single character repeatedly. This is almost a repeat of - the code for a repeated single character, but I haven't found a nice way of - commoning these up that doesn't require a test of the positive/negative - option for each character match. Maybe that wouldn't add very much to the - time taken, but character matching *is* what this is all about... */ - - case OP_NOTEXACT: - min = max = (ecode[1] << 8) + ecode[2]; - ecode += 3; - goto REPEATNOTCHAR; - - case OP_NOTUPTO: - case OP_NOTMINUPTO: - min = 0; - max = (ecode[1] << 8) + ecode[2]; - minimize = *ecode == OP_NOTMINUPTO; - ecode += 3; - goto REPEATNOTCHAR; - - case OP_NOTSTAR: - case OP_NOTMINSTAR: - case OP_NOTPLUS: - case OP_NOTMINPLUS: - case OP_NOTQUERY: - case OP_NOTMINQUERY: - c = *ecode++ - OP_NOTSTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single-character matches. We can give - up quickly if there are fewer than the minimum number of characters left in - the subject. */ - - REPEATNOTCHAR: - if (min > md->end_subject - eptr) return FALSE; - c = *ecode++; - - /* The code is duplicated for the caseless and caseful cases, for speed, - since matching characters is likely to be quite common. First, ensure the - minimum number of matches are present. If min = max, continue at the same - level without recursing. Otherwise, if minimizing, keep trying the rest of - the expression and advancing one matching character if failing, up to the - maximum. Alternatively, if maximizing, find the maximum number of - characters and work backwards. */ - - if ((ims & PCRE_CASELESS) != 0) - { - c = md->lcc[c]; - for (i = 1; i <= min; i++) - if (c == md->lcc[*eptr++]) return FALSE; - if (min == max) continue; - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || eptr >= md->end_subject || - c == md->lcc[*eptr++]) - return FALSE; - } - /* Control never gets here */ - } - else - { - const uschar *pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || c == md->lcc[*eptr]) break; - eptr++; - } - while (eptr >= pp) - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - return FALSE; - } - /* Control never gets here */ - } - - /* Caseful comparisons */ - - else - { - for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE; - if (min == max) continue; - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE; - } - /* Control never gets here */ - } - else - { - const uschar *pp = eptr; - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || c == *eptr) break; - eptr++; - } - while (eptr >= pp) - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; - return FALSE; - } - } - /* Control never gets here */ - - /* Match a single character type repeatedly; several different opcodes - share code. This is very similar to the code for single characters, but we - repeat it in the interests of efficiency. */ - - case OP_TYPEEXACT: - min = max = (ecode[1] << 8) + ecode[2]; - minimize = TRUE; - ecode += 3; - goto REPEATTYPE; - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - min = 0; - max = (ecode[1] << 8) + ecode[2]; - minimize = *ecode == OP_TYPEMINUPTO; - ecode += 3; - goto REPEATTYPE; - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - c = *ecode++ - OP_TYPESTAR; - minimize = (c & 1) != 0; - min = rep_min[c]; /* Pick up values from tables; */ - max = rep_max[c]; /* zero for max => infinity */ - if (max == 0) max = INT_MAX; - - /* Common code for all repeated single character type matches */ - - REPEATTYPE: - ctype = *ecode++; /* Code for the character type */ - - /* First, ensure the minimum number of matches are present. Use inline - code for maximizing the speed, and do the type test once at the start - (i.e. keep it out of the loop). Also we can test that there are at least - the minimum number of bytes before we start, except when doing '.' in - UTF8 mode. Leave the test in in all cases; in the special case we have - to test after each character. */ - - if (min > md->end_subject - eptr) return FALSE; - if (min > 0) switch(ctype) - { - case OP_ANY: + } + return FALSE; + } + } + + case OP_CHARS: + { + register int length = ecode[1]; + ecode += 2; + + if (length > md->end_subject - eptr) + return FALSE; + if ((ims & PCRE_CASELESS) != 0) { + while (length-- > 0) + if (md->lcc[*ecode++] != md->lcc[*eptr++]) + return FALSE; + } + else { + while (length-- > 0) + if (*ecode++ != *eptr++) + return FALSE; + } + } + break; + + case OP_EXACT: + min = max = (ecode[1] << 8) + ecode[2]; + ecode += 3; + goto REPEATCHAR; + + case OP_UPTO: + case OP_MINUPTO: + min = 0; + max = (ecode[1] << 8) + ecode[2]; + minimize = *ecode == OP_MINUPTO; + ecode += 3; + goto REPEATCHAR; + + case OP_STAR: + case OP_MINSTAR: + case OP_PLUS: + case OP_MINPLUS: + case OP_QUERY: + case OP_MINQUERY: + c = *ecode++ - OP_STAR; + minimize = (c & 1) != 0; + min = rep_min[c]; + max = rep_max[c]; + if (max == 0) + max = INT_MAX; + + REPEATCHAR: + if (min > md->end_subject - eptr) + return FALSE; + c = *ecode++; + + if ((ims & PCRE_CASELESS) != 0) { + c = md->lcc[c]; + for (i = 1; i <= min; i++) + if (c != md->lcc[*eptr++]) + return FALSE; + if (min == max) + continue; + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max || eptr >= md->end_subject + || c != md->lcc[*eptr++]) + return FALSE; + } + } + else { + const uschar *pp = eptr; + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || c != md->lcc[*eptr]) break; + eptr++; + } + while (eptr >= pp) + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + return FALSE; + } + } + + else { + for (i = 1; i <= min; i++) + if (c != *eptr++) + return FALSE; + if (min == max) + continue; + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max || eptr >= md->end_subject + || c != *eptr++) + return FALSE; + } + } + else { + const uschar *pp = eptr; + for (i = min; i < max; i++) { + if (eptr >= md->end_subject || c != *eptr) + break; + eptr++; + } + while (eptr >= pp) + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + return FALSE; + } + } + + case OP_NOT: + if (eptr >= md->end_subject) + return FALSE; + ecode++; + if ((ims & PCRE_CASELESS) != 0) { + if (md->lcc[*ecode++] == md->lcc[*eptr++]) + return FALSE; + } + else { + if (*ecode++ == *eptr++) + return FALSE; + } + break; + + case OP_NOTEXACT: + min = max = (ecode[1] << 8) + ecode[2]; + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTUPTO: + case OP_NOTMINUPTO: + min = 0; + max = (ecode[1] << 8) + ecode[2]; + minimize = *ecode == OP_NOTMINUPTO; + ecode += 3; + goto REPEATNOTCHAR; + + case OP_NOTSTAR: + case OP_NOTMINSTAR: + case OP_NOTPLUS: + case OP_NOTMINPLUS: + case OP_NOTQUERY: + case OP_NOTMINQUERY: + c = *ecode++ - OP_NOTSTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; + max = rep_max[c]; + if (max == 0) + max = INT_MAX; + + REPEATNOTCHAR: + if (min > md->end_subject - eptr) + return FALSE; + c = *ecode++; + + if ((ims & PCRE_CASELESS) != 0) { + c = md->lcc[c]; + for (i = 1; i <= min; i++) + if (c == md->lcc[*eptr++]) + return FALSE; + if (min == max) + continue; + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max || eptr >= md->end_subject + || c == md->lcc[*eptr++]) + return FALSE; + } + } + else { + const uschar *pp = eptr; + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || c == md->lcc[*eptr]) break; + eptr++; + } + while (eptr >= pp) + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + return FALSE; + } + } + + else { + for (i = 1; i <= min; i++) + if (c == *eptr++) + return FALSE; + if (min == max) + continue; + if (minimize) { + for (i = min;; i++) { + if (match + (eptr, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + if (i >= max || eptr >= md->end_subject + || c == *eptr++) + return FALSE; + } + } + else { + const uschar *pp = eptr; + for (i = min; i < max; i++) { + if (eptr >= md->end_subject || c == *eptr) + break; + eptr++; + } + while (eptr >= pp) + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; + return FALSE; + } + } + + case OP_TYPEEXACT: + min = max = (ecode[1] << 8) + ecode[2]; + minimize = TRUE; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + min = 0; + max = (ecode[1] << 8) + ecode[2]; + minimize = *ecode == OP_TYPEMINUPTO; + ecode += 3; + goto REPEATTYPE; + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + c = *ecode++ - OP_TYPESTAR; + minimize = (c & 1) != 0; + min = rep_min[c]; + max = rep_max[c]; + if (max == 0) + max = INT_MAX; + + REPEATTYPE: + ctype = *ecode++; + + if (min > md->end_subject - eptr) + return FALSE; + if (min > 0) + switch (ctype) { + case OP_ANY: #ifdef STR_PCRE_SUPPORT_UTF8 - if (md->utf8) - { - for (i = 1; i <= min; i++) - { - if (eptr >= md->end_subject || - (*eptr++ == '\n' && (ims & PCRE_DOTALL) == 0)) - return FALSE; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - break; - } + if (md->utf8) { + for (i = 1; i <= min; i++) { + if (eptr >= md->end_subject || + (*eptr++ == '\n' + && (ims & PCRE_DOTALL) == 0)) + return FALSE; + while (eptr < md->end_subject + && (*eptr & 0xc0) == 0x80) + eptr++; + } + break; + } #endif - /* Non-UTF8 can be faster */ - if ((ims & PCRE_DOTALL) == 0) - { for (i = 1; i <= min; i++) if (*eptr++ == '\n') return FALSE; } - else eptr += min; - break; - - case OP_NOT_DIGIT: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE; - break; - - case OP_DIGIT: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE; - break; - - case OP_NOT_WHITESPACE: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE; - break; - - case OP_WHITESPACE: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE; - break; - - case OP_NOT_WORDCHAR: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_word) != 0) - return FALSE; - break; - - case OP_WORDCHAR: - for (i = 1; i <= min; i++) - if ((md->ctypes[*eptr++] & ctype_word) == 0) - return FALSE; - break; - } - - /* If min = max, continue at the same level without recursing */ - - if (min == max) continue; - - /* If minimizing, we have to test the rest of the pattern before each - subsequent match. */ - - if (minimize) - { - for (i = min;; i++) - { - if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; - if (i >= max || eptr >= md->end_subject) return FALSE; - - c = *eptr++; - switch(ctype) - { - case OP_ANY: - if ((ims & PCRE_DOTALL) == 0 && c == '\n') return FALSE; + if ((ims & PCRE_DOTALL) == 0) { + for (i = 1; i <= min; i++) + if (*eptr++ == '\n') + return FALSE; + } + else + eptr += min; + break; + + case OP_NOT_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) != 0) + return FALSE; + break; + + case OP_DIGIT: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_digit) == 0) + return FALSE; + break; + + case OP_NOT_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) != 0) + return FALSE; + break; + + case OP_WHITESPACE: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_space) == 0) + return FALSE; + break; + + case OP_NOT_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) != 0) + return FALSE; + break; + + case OP_WORDCHAR: + for (i = 1; i <= min; i++) + if ((md->ctypes[*eptr++] & ctype_word) == 0) + return FALSE; + break; + } + + if (min == max) + continue; + + if (minimize) { + for (i = min;; i++) { + if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) + return TRUE; + if (i >= max || eptr >= md->end_subject) + return FALSE; + + c = *eptr++; + switch (ctype) { + case OP_ANY: + if ((ims & PCRE_DOTALL) == 0 && c == '\n') + return FALSE; #ifdef STR_PCRE_SUPPORT_UTF8 - if (md->utf8) - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; + if (md->utf8) + while (eptr < md->end_subject + && (*eptr & 0xc0) == 0x80) + eptr++; #endif - break; + break; - case OP_NOT_DIGIT: - if ((md->ctypes[c] & ctype_digit) != 0) return FALSE; - break; - - case OP_DIGIT: - if ((md->ctypes[c] & ctype_digit) == 0) return FALSE; - break; - - case OP_NOT_WHITESPACE: - if ((md->ctypes[c] & ctype_space) != 0) return FALSE; - break; - - case OP_WHITESPACE: - if ((md->ctypes[c] & ctype_space) == 0) return FALSE; - break; - - case OP_NOT_WORDCHAR: - if ((md->ctypes[c] & ctype_word) != 0) return FALSE; - break; - - case OP_WORDCHAR: - if ((md->ctypes[c] & ctype_word) == 0) return FALSE; - break; - } - } - /* Control never gets here */ - } - - /* If maximizing it is worth using inline code for speed, doing the type - test once at the start (i.e. keep it out of the loop). */ - - else - { - const uschar *pp = eptr; - switch(ctype) - { - case OP_ANY: - - /* Special code is required for UTF8, but when the maximum is unlimited - we don't need it. */ + case OP_NOT_DIGIT: + if ((md->ctypes[c] & ctype_digit) != 0) + return FALSE; + break; + + case OP_DIGIT: + if ((md->ctypes[c] & ctype_digit) == 0) + return FALSE; + break; + + case OP_NOT_WHITESPACE: + if ((md->ctypes[c] & ctype_space) != 0) + return FALSE; + break; + + case OP_WHITESPACE: + if ((md->ctypes[c] & ctype_space) == 0) + return FALSE; + break; + + case OP_NOT_WORDCHAR: + if ((md->ctypes[c] & ctype_word) != 0) + return FALSE; + break; + + case OP_WORDCHAR: + if ((md->ctypes[c] & ctype_word) == 0) + return FALSE; + break; + } + } + } + + else { + const uschar *pp = eptr; + switch (ctype) { + case OP_ANY: #ifdef STR_PCRE_SUPPORT_UTF8 - if (md->utf8 && max < INT_MAX) - { - if ((ims & PCRE_DOTALL) == 0) - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || *eptr++ == '\n') break; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - } - else - { - for (i = min; i < max; i++) - { - eptr++; - while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; - } - } - break; - } + if (md->utf8 && max < INT_MAX) { + if ((ims & PCRE_DOTALL) == 0) { + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || *eptr++ == '\n') + break; + while (eptr < md->end_subject + && (*eptr & 0xc0) == 0x80) + eptr++; + } + } + else { + for (i = min; i < max; i++) { + eptr++; + while (eptr < md->end_subject + && (*eptr & 0xc0) == 0x80) + eptr++; + } + } + break; + } #endif - /* Non-UTF8 can be faster */ - if ((ims & PCRE_DOTALL) == 0) - { - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || *eptr == '\n') break; - eptr++; - } - } - else - { - c = max - min; - if (c > md->end_subject - eptr) c = md->end_subject - eptr; - eptr += c; - } - break; - - case OP_NOT_DIGIT: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) - break; - eptr++; - } - break; - - case OP_DIGIT: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) - break; - eptr++; - } - break; - - case OP_NOT_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) - break; - eptr++; - } - break; - - case OP_WHITESPACE: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) - break; - eptr++; - } - break; - - case OP_NOT_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) - break; - eptr++; - } - break; - - case OP_WORDCHAR: - for (i = min; i < max; i++) - { - if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) - break; - eptr++; - } - break; - } - - while (eptr >= pp) - { - if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) - return TRUE; + if ((ims & PCRE_DOTALL) == 0) { + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || *eptr == '\n') break; + eptr++; + } + } + else { + c = max - min; + if (c > md->end_subject - eptr) + c = md->end_subject - eptr; + eptr += c; + } + break; + + case OP_NOT_DIGIT: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_digit) != 0) + break; + eptr++; + } + break; + + case OP_DIGIT: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_digit) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WHITESPACE: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_space) != 0) + break; + eptr++; + } + break; + + case OP_WHITESPACE: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_space) == 0) + break; + eptr++; + } + break; + + case OP_NOT_WORDCHAR: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_word) != 0) + break; + eptr++; + } + break; + + case OP_WORDCHAR: + for (i = min; i < max; i++) { + if (eptr >= md->end_subject + || (md->ctypes[*eptr] & ctype_word) == 0) + break; + eptr++; + } + break; + } + + while (eptr >= pp) { + if (match + (eptr--, ecode, offset_top, md, ims, eptrb, + 0)) return TRUE; #ifdef STR_PCRE_SUPPORT_UTF8 - if (md->utf8) - while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--; + if (md->utf8) + while (eptr > pp && (*eptr & 0xc0) == 0x80) + eptr--; #endif - } - return FALSE; - } - /* Control never gets here */ + } + return FALSE; + } - /* There's been some horrible disaster. */ + default: - default: + md->errorcode = PCRE_ERROR_UNKNOWN_NODE; + return FALSE; + } - md->errorcode = PCRE_ERROR_UNKNOWN_NODE; - return FALSE; - } - - /* Do not stick any code in here without much thought; it is assumed - that "continue" in the code above comes out to here to repeat the main - loop. */ - - } -/* Control never reaches here */ + } } -/************************************************* -* Execute a Regular Expression * -*************************************************/ - -/* This function applies a compiled re to a subject string and picks out -portions of the string if it matches. Two elements in the vector are set for -each substring: the offsets to the start and end of the substring. - -Arguments: - external_re points to the compiled expression - external_extra points to "hints" from pcre_study() or is NULL - subject points to the subject string - length length of subject string (may contain binary zeros) - start_offset where to start in the subject string - options option bits - offsets points to a vector of ints to be filled in with offsets - offsetcount the number of elements in the vector - -Returns: > 0 => success; value is the number of elements filled in - = 0 => success, but offsets is not big enough - -1 => failed to match - < -1 => some kind of unexpected problem -*/ - int -pcre_exec(const pcre *external_re, const pcre_extra *external_extra, - const char *subject, int length, int start_offset, int options, int *offsets, - int offsetcount) +pcre_exec(const pcre * external_re, const pcre_extra * external_extra, + const char *subject, int length, int start_offset, int options, + int *offsets, int offsetcount) { -int resetcount, ocount; -int first_char = -1; -int req_char = -1; -int req_char2 = -1; -unsigned long int ims = 0; -match_data match_block; -const uschar *start_bits = NULL; -const uschar *start_match = (const uschar *)subject + start_offset; -const uschar *end_subject; -const uschar *req_char_ptr = start_match - 1; -const real_pcre *re = (const real_pcre *)external_re; -const real_pcre_extra *extra = (const real_pcre_extra *)external_extra; -BOOL using_temporary_offsets = FALSE; -BOOL anchored; -BOOL startline; - -if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; - -if (re == NULL || subject == NULL || - (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; -if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; - -anchored = ((re->options | options) & PCRE_ANCHORED) != 0; -startline = (re->options & PCRE_STARTLINE) != 0; - -match_block.start_pattern = re->code; -match_block.start_subject = (const uschar *)subject; -match_block.end_subject = match_block.start_subject + length; -end_subject = match_block.end_subject; - -match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; -match_block.utf8 = (re->options & PCRE_UTF8) != 0; - -match_block.notbol = (options & PCRE_NOTBOL) != 0; -match_block.noteol = (options & PCRE_NOTEOL) != 0; -match_block.notempty = (options & PCRE_NOTEMPTY) != 0; - -match_block.errorcode = PCRE_ERROR_NOMATCH; /* Default error */ - -match_block.lcc = re->tables + lcc_offset; -match_block.ctypes = re->tables + ctypes_offset; - -/* The ims options can vary during the matching as a result of the presence -of (?ims) items in the pattern. They are kept in a local variable so that -restoring at the exit of a group is easy. */ - -ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); - -/* If the expression has got more back references than the offsets supplied can -hold, we get a temporary bit of working store to use during the matching. -Otherwise, we can use the vector supplied, rounding down its size to a multiple -of 3. */ - -ocount = offsetcount - (offsetcount % 3); - -if (re->top_backref > 0 && re->top_backref >= ocount/3) - { - ocount = re->top_backref * 3 + 3; - match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); - if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; - using_temporary_offsets = TRUE; - - } -else match_block.offset_vector = offsets; - -match_block.offset_end = ocount; -match_block.offset_max = (2*ocount)/3; -match_block.offset_overflow = FALSE; - -/* Compute the minimum number of offsets that we need to reset each time. Doing -this makes a huge difference to execution time when there aren't many brackets -in the pattern. */ - -resetcount = 2 + re->top_bracket * 2; -if (resetcount > offsetcount) resetcount = ocount; - -/* Reset the working variable associated with each extraction. These should -never be used unless previously set, but they get saved and restored, and so we -initialize them to avoid reading uninitialized locations. */ - -if (match_block.offset_vector != NULL) - { - register int *iptr = match_block.offset_vector + ocount; - register int *iend = iptr - resetcount/2 + 1; - while (--iptr >= iend) *iptr = -1; - } - -/* Set up the first character to match, if available. The first_char value is -never set for an anchored regular expression, but the anchoring may be forced -at run time, so we have to test for anchoring. The first char may be unset for -an unanchored pattern, of course. If there's no first char and the pattern was -studied, there may be a bitmap of possible first characters. */ - -if (!anchored) - { - if ((re->options & PCRE_FIRSTSET) != 0) - { - first_char = re->first_char; - if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char]; - } - else - if (!startline && extra != NULL && - (extra->options & PCRE_STUDY_MAPPED) != 0) - start_bits = extra->start_bits; - } - -/* For anchored or unanchored matches, there may be a "last known required -character" set. If the PCRE_CASELESS is set, implying that the match starts -caselessly, or if there are any changes of this flag within the regex, set up -both cases of the character. Otherwise set the two values the same, which will -avoid duplicate testing (which takes significant time). This covers the vast -majority of cases. It will be suboptimal when the case flag changes in a regex -and the required character in fact is caseful. */ - -if ((re->options & PCRE_REQCHSET) != 0) - { - req_char = re->req_char; - req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)? - (re->tables + fcc_offset)[req_char] : req_char; - } - -/* Loop for handling unanchored repeated matching attempts; for anchored regexs -the loop runs just once. */ - -do - { - int rc; - register int *iptr = match_block.offset_vector; - register int *iend = iptr + resetcount; - - /* Reset the maximum number of extractions we might see. */ - - while (iptr < iend) *iptr++ = -1; - - /* Advance to a unique first char if possible */ - - if (first_char >= 0) - { - if ((ims & PCRE_CASELESS) != 0) - while (start_match < end_subject && - match_block.lcc[*start_match] != first_char) - start_match++; - else - while (start_match < end_subject && *start_match != first_char) - start_match++; - } - - /* Or to just after \n for a multiline match if possible */ - - else if (startline) - { - if (start_match > match_block.start_subject + start_offset) - { - while (start_match < end_subject && start_match[-1] != '\n') - start_match++; - } - } - - /* Or to a non-unique first char after study */ - - else if (start_bits != NULL) - { - while (start_match < end_subject) - { - register int c = *start_match; - if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break; - } - } - - /* If req_char is set, we know that that character must appear in the subject - for the match to succeed. If the first character is set, req_char must be - later in the subject; otherwise the test starts at the match point. This - optimization can save a huge amount of backtracking in patterns with nested - unlimited repeats that aren't going to match. We don't know what the state of - case matching may be when this character is hit, so test for it in both its - cases if necessary. However, the different cased versions will not be set up - unless PCRE_CASELESS was given or the casing state changes within the regex. - Writing separate code makes it go faster, as does using an autoincrement and - backing off on a match. */ - - if (req_char >= 0) - { - register const uschar *p = start_match + ((first_char >= 0)? 1 : 0); - - /* We don't need to repeat the search if we haven't yet reached the - place we found it at last time. */ - - if (p > req_char_ptr) - { - /* Do a single test if no case difference is set up */ - - if (req_char == req_char2) - { - while (p < end_subject) - { - if (*p++ == req_char) { p--; break; } - } - } - - /* Otherwise test for either case */ - - else - { - while (p < end_subject) - { - register int pp = *p++; - if (pp == req_char || pp == req_char2) { p--; break; } - } - } - - /* If we can't find the required character, break the matching loop */ - - if (p >= end_subject) break; - - /* If we have found the required character, save the point where we - found it, so that we don't search again next time round the loop if - the start hasn't passed this character yet. */ - - req_char_ptr = p; - } - } - - /* When a match occurs, substrings will be set for all internal extractions; - we just need to set up the whole thing as substring 0 before returning. If - there were too many extractions, set the return code to zero. In the case - where we had to get some local store to hold offsets for backreferences, copy - those back references that we can. In this case there need not be overflow - if certain parts of the pattern were not used. */ - - match_block.start_match = start_match; - if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup)) - continue; - - /* Copy the offset information from temporary store if necessary */ - - if (using_temporary_offsets) - { - if (offsetcount >= 4) - { - memcpy(offsets + 2, match_block.offset_vector + 2, - (offsetcount - 2) * sizeof(int)); - - } - if (match_block.end_offset_top > offsetcount) - match_block.offset_overflow = TRUE; - - (pcre_free)(match_block.offset_vector); - } - - rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; + int resetcount, ocount; + int first_char = -1; + int req_char = -1; + int req_char2 = -1; + unsigned long int ims = 0; + match_data match_block; + const uschar *start_bits = NULL; + const uschar *start_match = (const uschar *)subject + start_offset; + const uschar *end_subject; + const uschar *req_char_ptr = start_match - 1; + const pcre_st *re = (const pcre_st *)external_re; + const pcre_extra_st *extra = (const pcre_extra_st *)external_extra; + BOOL using_temporary_offsets = FALSE; + BOOL anchored; + BOOL startline; + + if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) + return PCRE_ERROR_BADOPTION; + + if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) + return PCRE_ERROR_NULL; + if (re->magic_number != MAGIC_NUMBER) + return PCRE_ERROR_BADMAGIC; + + anchored = ((re->options | options) & PCRE_ANCHORED) != 0; + startline = (re->options & PCRE_STARTLINE) != 0; + + match_block.start_pattern = re->code; + match_block.start_subject = (const uschar *)subject; + match_block.end_subject = match_block.start_subject + length; + end_subject = match_block.end_subject; + + match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; + match_block.utf8 = (re->options & PCRE_UTF8) != 0; + + match_block.notbol = (options & PCRE_NOTBOL) != 0; + match_block.noteol = (options & PCRE_NOTEOL) != 0; + match_block.notempty = (options & PCRE_NOTEMPTY) != 0; + + match_block.errorcode = PCRE_ERROR_NOMATCH; + + match_block.lcc = re->tables + lcc_offset; + match_block.ctypes = re->tables + ctypes_offset; + + ims = re->options & (PCRE_CASELESS | PCRE_MULTILINE | PCRE_DOTALL); + + ocount = offsetcount - (offsetcount % 3); + + if (re->top_backref > 0 && re->top_backref >= ocount / 3) { + ocount = re->top_backref * 3 + 3; + match_block.offset_vector = + (int *)(pcre_malloc) (ocount * sizeof (int)); + if (match_block.offset_vector == NULL) + return PCRE_ERROR_NOMEMORY; + using_temporary_offsets = TRUE; + + } + else + match_block.offset_vector = offsets; + + match_block.offset_end = ocount; + match_block.offset_max = (2 * ocount) / 3; + match_block.offset_overflow = FALSE; + + resetcount = 2 + re->top_bracket * 2; + if (resetcount > offsetcount) + resetcount = ocount; + + if (match_block.offset_vector != NULL) { + register int *iptr = match_block.offset_vector + ocount; + register int *iend = iptr - resetcount / 2 + 1; + while (--iptr >= iend) + *iptr = -1; + } + + if (!anchored) { + if ((re->options & PCRE_FIRSTSET) != 0) { + first_char = re->first_char; + if ((ims & PCRE_CASELESS) != 0) + first_char = match_block.lcc[first_char]; + } + else + if (!startline && extra != NULL && + (extra->options & PCRE_STUDY_MAPPED) != 0) + start_bits = extra->start_bits; + } + + if ((re->options & PCRE_REQCHSET) != 0) { + req_char = re->req_char; + req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0) ? + (re->tables + fcc_offset)[req_char] : req_char; + } + + do { + int rc; + register int *iptr = match_block.offset_vector; + register int *iend = iptr + resetcount; + + while (iptr < iend) + *iptr++ = -1; + + if (first_char >= 0) { + if ((ims & PCRE_CASELESS) != 0) + while (start_match < end_subject && + match_block.lcc[*start_match] != first_char) + start_match++; + else + while (start_match < end_subject + && *start_match != first_char) start_match++; + } + + else if (startline) { + if (start_match > match_block.start_subject + start_offset) { + while (start_match < end_subject && start_match[-1] != '\n') + start_match++; + } + } + + else if (start_bits != NULL) { + while (start_match < end_subject) { + register int c = *start_match; + if ((start_bits[c / 8] & (1 << (c & 7))) == 0) + start_match++; + else + break; + } + } + + if (req_char >= 0) { + register const uschar *p = + start_match + ((first_char >= 0) ? 1 : 0); + + if (p > req_char_ptr) { + if (req_char == req_char2) { + while (p < end_subject) { + if (*p++ == req_char) { + p--; + break; + } + } + } + + else { + while (p < end_subject) { + register int pp = *p++; + if (pp == req_char || pp == req_char2) { + p--; + break; + } + } + } + + if (p >= end_subject) + break; + + req_char_ptr = p; + } + } + + match_block.start_match = start_match; + if (!match + (start_match, re->code, 2, &match_block, ims, NULL, + match_isgroup)) continue; + + if (using_temporary_offsets) { + if (offsetcount >= 4) { + memcpy(offsets + 2, match_block.offset_vector + 2, + (offsetcount - 2) * sizeof (int)); + + } + if (match_block.end_offset_top > offsetcount) + match_block.offset_overflow = TRUE; + + (pcre_free) (match_block.offset_vector); + } + + rc = match_block.offset_overflow ? 0 : match_block.end_offset_top / 2; + + if (offsetcount < 2) + rc = 0; + else { + offsets[0] = start_match - match_block.start_subject; + offsets[1] = + match_block.end_match_ptr - match_block.start_subject; + } + + return rc; + } + + while (!anchored && + match_block.errorcode == PCRE_ERROR_NOMATCH && + start_match++ < end_subject); - 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; - } - - return rc; - } - -/* This "while" is the end of the "do" above */ - -while (!anchored && - match_block.errorcode == PCRE_ERROR_NOMATCH && - start_match++ < end_subject); + if (using_temporary_offsets) { -if (using_temporary_offsets) - { + (pcre_free) (match_block.offset_vector); + } - (pcre_free)(match_block.offset_vector); - } - -return match_block.errorcode; + return match_block.errorcode; } -/* ____ END pcre.c ____ */ - -/* ____ BEGIN study.c ____ */ - -/* Include the internals header, which itself includes Standard C headers plus -the external pcre header. */ - -/************************************************* -* Set a bit and maybe its alternate case * -*************************************************/ - -/* Given a character, set its bit in the table, and also the bit for the other -version of a letter if we are caseless. - -Arguments: - start_bits points to the bit map - c is the character - caseless the caseless flag - cd the block with char table pointers - -Returns: nothing -*/ - static void -set_bit(uschar *start_bits, int c, BOOL caseless, compile_data *cd) +set_bit(uschar * start_bits, int c, BOOL caseless, compile_data * cd) { -start_bits[c/8] |= (1 << (c&7)); -if (caseless && (cd->ctypes[c] & ctype_letter) != 0) - start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); + start_bits[c / 8] |= (1 << (c & 7)); + if (caseless && (cd->ctypes[c] & ctype_letter) != 0) + start_bits[cd->fcc[c] / 8] |= (1 << (cd->fcc[c] & 7)); } -/************************************************* -* Create bitmap of starting chars * -*************************************************/ - -/* This function scans a compiled unanchored expression and attempts to build a -bitmap of the set of initial characters. If it can't, it returns FALSE. As time -goes by, we may be able to get more clever at doing this. - -Arguments: - code points to an expression - start_bits points to a 32-byte table, initialized to 0 - caseless the current state of the caseless flag - cd the block with char table pointers - -Returns: TRUE if table built, FALSE otherwise -*/ - static BOOL -set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, - compile_data *cd) +set_start_bits(const uschar * code, uschar * start_bits, BOOL caseless, + compile_data * cd) { -register int c; + register int c; -/* This next statement and the later reference to dummy are here in order to -trick the optimizer of the IBM C compiler for OS/2 into generating correct -code. Apparently IBM isn't going to fix the problem, and we would rather not -disable optimization (in this module it actually makes a big difference, and -the pcre module can use all the optimization it can get). */ - -volatile int dummy; - -do - { - const uschar *tcode = code + 3; - BOOL try_next = TRUE; - - while (try_next) - { - /* If a branch starts with a bracket or a positive lookahead assertion, - recurse to set bits from within them. That's all for this branch. */ - - if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) - { - if (!set_start_bits(tcode, start_bits, caseless, cd)) - return FALSE; - try_next = FALSE; - } - - else switch(*tcode) - { - default: - return FALSE; - - /* Skip over extended extraction bracket number */ - - case OP_BRANUMBER: - tcode += 3; - break; - - /* Skip over lookbehind and negative lookahead assertions */ - - case OP_ASSERT_NOT: - case OP_ASSERTBACK: - case OP_ASSERTBACK_NOT: - do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); - tcode += 3; - break; - - /* Skip over an option setting, changing the caseless flag */ - - case OP_OPT: - caseless = (tcode[1] & PCRE_CASELESS) != 0; - tcode += 2; - break; - - /* BRAZERO does the bracket, but carries on. */ - - case OP_BRAZERO: - case OP_BRAMINZERO: - if (!set_start_bits(++tcode, start_bits, caseless, cd)) - return FALSE; - dummy = 1; - do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); - tcode += 3; - break; - - /* Single-char * or ? sets the bit and tries the next item */ - - case OP_STAR: - case OP_MINSTAR: - case OP_QUERY: - case OP_MINQUERY: - set_bit(start_bits, tcode[1], caseless, cd); - tcode += 2; - break; - - /* Single-char upto sets the bit and tries the next */ - - case OP_UPTO: - case OP_MINUPTO: - set_bit(start_bits, tcode[3], caseless, cd); - tcode += 4; - break; - - /* At least one single char sets the bit and stops */ - - case OP_EXACT: /* Fall through */ - tcode++; - - case OP_CHARS: /* Fall through */ - tcode++; - - case OP_PLUS: - case OP_MINPLUS: - set_bit(start_bits, tcode[1], caseless, cd); - try_next = FALSE; - break; - - /* Single character type sets the bits and stops */ - - case OP_NOT_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_digit]; - try_next = FALSE; - break; - - case OP_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_digit]; - try_next = FALSE; - break; - - case OP_NOT_WHITESPACE: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_space]; - try_next = FALSE; - break; - - case OP_WHITESPACE: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_space]; - try_next = FALSE; - break; - - case OP_NOT_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_word]; - try_next = FALSE; - break; - - case OP_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_word]; - try_next = FALSE; - break; - - /* One or more character type fudges the pointer and restarts, knowing - it will hit a single character type and stop there. */ - - case OP_TYPEPLUS: - case OP_TYPEMINPLUS: - tcode++; - break; - - case OP_TYPEEXACT: - tcode += 3; - break; - - /* Zero or more repeats of character types set the bits and then - try again. */ - - case OP_TYPEUPTO: - case OP_TYPEMINUPTO: - tcode += 2; /* Fall through */ - - case OP_TYPESTAR: - case OP_TYPEMINSTAR: - case OP_TYPEQUERY: - case OP_TYPEMINQUERY: - switch(tcode[1]) - { - case OP_NOT_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_digit]; - break; - - case OP_DIGIT: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_digit]; - break; - - case OP_NOT_WHITESPACE: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_space]; - break; - - case OP_WHITESPACE: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_space]; - break; - - case OP_NOT_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= ~cd->cbits[c+cbit_word]; - break; - - case OP_WORDCHAR: - for (c = 0; c < 32; c++) - start_bits[c] |= cd->cbits[c+cbit_word]; - break; - } - - tcode += 2; - break; - - /* Character class: set the bits and either carry on or not, - according to the repeat count. */ - - case OP_CLASS: - { - tcode++; - for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; - tcode += 32; - switch (*tcode) - { - case OP_CRSTAR: - case OP_CRMINSTAR: - case OP_CRQUERY: - case OP_CRMINQUERY: - tcode++; - break; - - case OP_CRRANGE: - case OP_CRMINRANGE: - if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5; - else try_next = FALSE; - break; - - default: - try_next = FALSE; - break; - } - } - break; - - } - } + volatile int dummy; - code += (code[1] << 8) + code[2]; /* Advance to next branch */ - } -while (*code == OP_ALT); -return TRUE; + do { + const uschar *tcode = code + 3; + BOOL try_next = TRUE; + + while (try_next) { + if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) { + if (!set_start_bits(tcode, start_bits, caseless, cd)) + return FALSE; + try_next = FALSE; + } + + else + switch (*tcode) { + default: + return FALSE; + + case OP_BRANUMBER: + tcode += 3; + break; + + case OP_ASSERT_NOT: + case OP_ASSERTBACK: + case OP_ASSERTBACK_NOT: + do + tcode += (tcode[1] << 8) + tcode[2]; + while (*tcode == OP_ALT); + tcode += 3; + break; + + case OP_OPT: + caseless = (tcode[1] & PCRE_CASELESS) != 0; + tcode += 2; + break; + + case OP_BRAZERO: + case OP_BRAMINZERO: + if (!set_start_bits + (++tcode, start_bits, caseless, cd)) return FALSE; + dummy = 1; + do + tcode += (tcode[1] << 8) + tcode[2]; + while (*tcode == OP_ALT); + tcode += 3; + break; + + case OP_STAR: + case OP_MINSTAR: + case OP_QUERY: + case OP_MINQUERY: + set_bit(start_bits, tcode[1], caseless, cd); + tcode += 2; + break; + + case OP_UPTO: + case OP_MINUPTO: + set_bit(start_bits, tcode[3], caseless, cd); + tcode += 4; + break; + + case OP_EXACT: + tcode++; + + case OP_CHARS: + tcode++; + + case OP_PLUS: + case OP_MINPLUS: + set_bit(start_bits, tcode[1], caseless, cd); + try_next = FALSE; + break; + + case OP_NOT_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c + cbit_digit]; + try_next = FALSE; + break; + + case OP_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c + cbit_digit]; + try_next = FALSE; + break; + + case OP_NOT_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c + cbit_space]; + try_next = FALSE; + break; + + case OP_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c + cbit_space]; + try_next = FALSE; + break; + + case OP_NOT_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= ~cd->cbits[c + cbit_word]; + try_next = FALSE; + break; + + case OP_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c + cbit_word]; + try_next = FALSE; + break; + + case OP_TYPEPLUS: + case OP_TYPEMINPLUS: + tcode++; + break; + + case OP_TYPEEXACT: + tcode += 3; + break; + + case OP_TYPEUPTO: + case OP_TYPEMINUPTO: + tcode += 2; + + case OP_TYPESTAR: + case OP_TYPEMINSTAR: + case OP_TYPEQUERY: + case OP_TYPEMINQUERY: + switch (tcode[1]) { + case OP_NOT_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= + ~cd->cbits[c + cbit_digit]; + break; + + case OP_DIGIT: + for (c = 0; c < 32; c++) + start_bits[c] |= + cd->cbits[c + cbit_digit]; + break; + + case OP_NOT_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= + ~cd->cbits[c + cbit_space]; + break; + + case OP_WHITESPACE: + for (c = 0; c < 32; c++) + start_bits[c] |= + cd->cbits[c + cbit_space]; + break; + + case OP_NOT_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= + ~cd->cbits[c + cbit_word]; + break; + + case OP_WORDCHAR: + for (c = 0; c < 32; c++) + start_bits[c] |= cd->cbits[c + cbit_word]; + break; + } + + tcode += 2; + break; + + case OP_CLASS: + { + tcode++; + for (c = 0; c < 32; c++) + start_bits[c] |= tcode[c]; + tcode += 32; + switch (*tcode) { + case OP_CRSTAR: + case OP_CRMINSTAR: + case OP_CRQUERY: + case OP_CRMINQUERY: + tcode++; + break; + + case OP_CRRANGE: + case OP_CRMINRANGE: + if (((tcode[1] << 8) + tcode[2]) == 0) + tcode += 5; + else + try_next = FALSE; + break; + + default: + try_next = FALSE; + break; + } + } + break; + + } + } + + code += (code[1] << 8) + code[2]; + } + while (*code == OP_ALT); + return TRUE; } -/************************************************* -* Study a compiled expression * -*************************************************/ - -/* This function is handed a compiled expression that it must study to produce -information that will speed up the matching. It returns a pcre_extra block -which then gets handed back to pcre_exec(). - -Arguments: - re points to the compiled expression - options contains option bits - errorptr points to where to place error messages; - set NULL unless error - -Returns: pointer to a pcre_extra block, - NULL on error or if no optimization possible -*/ - -pcre_extra * -pcre_study(const pcre *external_re, int options, const char **errorptr) +pcre_extra *pcre_study(const pcre * external_re, int options, + const char **errorptr) { -uschar start_bits[32]; -real_pcre_extra *extra; -const real_pcre *re = (const real_pcre *)external_re; -compile_data compile_block; - -*errorptr = NULL; - -if (re == NULL || re->magic_number != MAGIC_NUMBER) - { - *errorptr = "argument is not a compiled regular expression"; - return NULL; - } - -if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) - { - *errorptr = "unknown or incorrect option bit(s) set"; - return NULL; - } - -/* For an anchored pattern, or an unchored pattern that has a first char, or a -multiline pattern that matches only at "line starts", no further processing at -present. */ - -if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) - return NULL; - -/* Set the character tables in the block which is passed around */ - -compile_block.lcc = re->tables + lcc_offset; -compile_block.fcc = re->tables + fcc_offset; -compile_block.cbits = re->tables + cbits_offset; -compile_block.ctypes = re->tables + ctypes_offset; + uschar start_bits[32]; + pcre_extra_st *extra; + const pcre_st *re = (const pcre_st *)external_re; + compile_data compile_block; + + *errorptr = NULL; + + if (re == NULL || re->magic_number != MAGIC_NUMBER) { + *errorptr = "argument is not a compiled regular expression"; + return NULL; + } + + if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) { + *errorptr = "unknown or incorrect option bit(s) set"; + return NULL; + } + + if ((re->options & (PCRE_ANCHORED | PCRE_FIRSTSET | PCRE_STARTLINE)) != 0) + return NULL; + + compile_block.lcc = re->tables + lcc_offset; + compile_block.fcc = re->tables + fcc_offset; + compile_block.cbits = re->tables + cbits_offset; + compile_block.ctypes = re->tables + ctypes_offset; + + memset(start_bits, 0, 32 * sizeof (uschar)); + if (!set_start_bits + (re->code, start_bits, (re->options & PCRE_CASELESS) != 0, + &compile_block)) return NULL; + + extra = (pcre_extra_st *) (pcre_malloc) (sizeof (pcre_extra_st)); + + if (extra == NULL) { + *errorptr = "failed to get memory"; + return NULL; + } -/* See if we can find a fixed set of initial characters for the pattern. */ + extra->options = PCRE_STUDY_MAPPED; + memcpy(extra->start_bits, start_bits, sizeof (start_bits)); -memset(start_bits, 0, 32 * sizeof(uschar)); -if (!set_start_bits(re->code, start_bits, (re->options & PCRE_CASELESS) != 0, - &compile_block)) return NULL; - -/* Get an "extra" block and put the information therein. */ - -extra = (real_pcre_extra *)(pcre_malloc)(sizeof(real_pcre_extra)); - -if (extra == NULL) - { - *errorptr = "failed to get memory"; - return NULL; - } - -extra->options = PCRE_STUDY_MAPPED; -memcpy(extra->start_bits, start_bits, sizeof(start_bits)); - -return (pcre_extra *)extra; + return (pcre_extra *) extra; } -/* ____ END study.c ____ */ - -/* ____ BEGIN get.c ____ */ - -/* This module contains some convenience functions for extracting substrings -from the subject string after a regex match has succeeded. The original idea -for these functions came from Scott Wimer . */ - -/* Include the internals header, which itself includes Standard C headers plus -the external pcre header. */ - -/************************************************* -* Copy captured string to given buffer * -*************************************************/ - -/* This function copies a single captured substring into a given buffer. -Note that we use memcpy() rather than strncpy() in case there are binary zeros -in the string. - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringnumber the number of the required substring - buffer where to put the substring - size the size of the buffer - -Returns: if successful: - the length of the copied string, not including the zero - that is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) buffer too small - PCRE_ERROR_NOSUBSTRING (-7) no such captured substring -*/ - int pcre_copy_substring(const char *subject, int *ovector, int stringcount, - int stringnumber, char *buffer, int size) + int stringnumber, char *buffer, int size) { -int yield; -if (stringnumber < 0 || stringnumber >= stringcount) - return PCRE_ERROR_NOSUBSTRING; -stringnumber *= 2; -yield = ovector[stringnumber+1] - ovector[stringnumber]; -if (size < yield + 1) return PCRE_ERROR_NOMEMORY; -memcpy(buffer, subject + ovector[stringnumber], yield); -buffer[yield] = 0; -return yield; + int yield; + if (stringnumber < 0 || stringnumber >= stringcount) + return PCRE_ERROR_NOSUBSTRING; + stringnumber *= 2; + yield = ovector[stringnumber + 1] - ovector[stringnumber]; + if (size < yield + 1) + return PCRE_ERROR_NOMEMORY; + memcpy(buffer, subject + ovector[stringnumber], yield); + buffer[yield] = 0; + return yield; } -/************************************************* -* Copy all captured strings to new store * -*************************************************/ - -/* This function gets one chunk of store and builds a list of pointers and all -of the captured substrings in it. A NULL pointer is put on the end of the list. - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - listptr set to point to the list of pointers - -Returns: if successful: 0 - if not successful: - PCRE_ERROR_NOMEMORY (-6) failed to get store -*/ - int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, - const char ***listptr) + const char ***listptr) { -int i; -int size = sizeof(char *); -int double_count = stringcount * 2; -char **stringlist; -char *p; - -for (i = 0; i < double_count; i += 2) - size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; - -stringlist = (char **)(pcre_malloc)(size); -if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; - -*listptr = (const char **)stringlist; -p = (char *)(stringlist + stringcount + 1); - -for (i = 0; i < double_count; i += 2) - { - int len = ovector[i+1] - ovector[i]; - memcpy(p, subject + ovector[i], len); - *stringlist++ = p; - p += len; - *p++ = 0; - } + int i; + int size = sizeof (char *); + int double_count = stringcount * 2; + char **stringlist; + char *p; + + for (i = 0; i < double_count; i += 2) + size += sizeof (char *) + ovector[i + 1] - ovector[i] + 1; + + stringlist = (char **)(pcre_malloc) (size); + if (stringlist == NULL) + return PCRE_ERROR_NOMEMORY; + + *listptr = (const char **)stringlist; + p = (char *)(stringlist + stringcount + 1); + + for (i = 0; i < double_count; i += 2) { + int len = ovector[i + 1] - ovector[i]; + memcpy(p, subject + ovector[i], len); + *stringlist++ = p; + p += len; + *p++ = 0; + } -*stringlist = NULL; -return 0; + *stringlist = NULL; + return 0; } -/************************************************* -* Free store obtained by get_substring_list * -*************************************************/ - -/* This function exists for the benefit of people calling PCRE from non-C -programs that can call its functions, but not free() or (pcre_free)() directly. - -Argument: the result of a previous pcre_get_substring_list() -Returns: nothing -*/ - -void -pcre_free_substring_list(const char **pointer) +void pcre_free_substring_list(const char **pointer) { -(pcre_free)((void *)pointer); + (pcre_free) ((void *)pointer); } -/************************************************* -* Copy captured string to new store * -*************************************************/ - -/* This function copies a single captured substring into a piece of new -store - -Arguments: - subject the subject string that was matched - ovector pointer to the offsets table - stringcount the number of substrings that were captured - (i.e. the yield of the pcre_exec call, unless - that was zero, in which case it should be 1/3 - of the offset table size) - stringnumber the number of the required substring - stringptr where to put a pointer to the substring - -Returns: if successful: - the length of the string, not including the zero that - is put on the end; can be zero - if not successful: - PCRE_ERROR_NOMEMORY (-6) failed to get store - PCRE_ERROR_NOSUBSTRING (-7) substring not present -*/ - int pcre_get_substring(const char *subject, int *ovector, int stringcount, - int stringnumber, const char **stringptr) + int stringnumber, const char **stringptr) { -int yield; -char *substring; -if (stringnumber < 0 || stringnumber >= stringcount) - return PCRE_ERROR_NOSUBSTRING; -stringnumber *= 2; -yield = ovector[stringnumber+1] - ovector[stringnumber]; -substring = (char *)(pcre_malloc)(yield + 1); -if (substring == NULL) return PCRE_ERROR_NOMEMORY; -memcpy(substring, subject + ovector[stringnumber], yield); -substring[yield] = 0; -*stringptr = substring; -return yield; + int yield; + char *substring; + if (stringnumber < 0 || stringnumber >= stringcount) + return PCRE_ERROR_NOSUBSTRING; + stringnumber *= 2; + yield = ovector[stringnumber + 1] - ovector[stringnumber]; + substring = (char *)(pcre_malloc) (yield + 1); + if (substring == NULL) + return PCRE_ERROR_NOMEMORY; + memcpy(substring, subject + ovector[stringnumber], yield); + substring[yield] = 0; + *stringptr = substring; + return yield; } -/************************************************* -* Free store obtained by get_substring * -*************************************************/ - -/* This function exists for the benefit of people calling PCRE from non-C -programs that can call its functions, but not free() or (pcre_free)() directly. - -Argument: the result of a previous pcre_get_substring() -Returns: nothing -*/ - -void -pcre_free_substring(const char *pointer) +void pcre_free_substring(const char *pointer) { -(pcre_free)((void *)pointer); + (pcre_free) ((void *)pointer); } -/* ____ END get.c ____ */ - -#endif /* !STR_PCRE_GENTAB */ - -/* ____ BEGIN maketables.c ____ */ - -/* This file is compiled on its own as part of the PCRE library. However, -it is also included in the compilation of dftables.c, in which case the macro -DFTABLES is defined. */ - -/************************************************* -* Create PCRE character tables * -*************************************************/ - -/* This function builds a set of character tables for use by PCRE and returns -a pointer to them. They are build using the ctype functions, and consequently -their contents will depend upon the current locale setting. When compiled as -part of the library, the store is obtained via pcre_malloc(), but when compiled -inside dftables, use malloc(). - -Arguments: none -Returns: pointer to the contiguous block of data -*/ +#endif -const unsigned char * -pcre_maketables(void) +const unsigned char *pcre_maketables(void) { -unsigned char *yield, *p; -int i; + unsigned char *yield, *p; + int i; -#ifndef STR_PCRE_GENTAB -yield = (unsigned char*)(pcre_malloc)(tables_length); +#ifndef STR_PCRE_TAB + yield = (unsigned char *)(pcre_malloc) (tables_length); #else -yield = (unsigned char*)malloc(tables_length); + yield = (unsigned char *)malloc(tables_length); #endif -if (yield == NULL) return NULL; -p = yield; - -/* First comes the lower casing table */ - -for (i = 0; i < 256; i++) *p++ = tolower(i); - -/* Next the case-flipping table */ + if (yield == NULL) + return NULL; + p = yield; + + for (i = 0; i < 256; i++) + *p++ = tolower(i); + + for (i = 0; i < 256; i++) + *p++ = islower(i) ? toupper(i) : tolower(i); + + memset(p, 0, cbit_length); + for (i = 0; i < 256; i++) { + if (isdigit(i)) { + p[cbit_digit + i / 8] |= 1 << (i & 7); + p[cbit_word + i / 8] |= 1 << (i & 7); + } + if (isupper(i)) { + p[cbit_upper + i / 8] |= 1 << (i & 7); + p[cbit_word + i / 8] |= 1 << (i & 7); + } + if (islower(i)) { + p[cbit_lower + i / 8] |= 1 << (i & 7); + p[cbit_word + i / 8] |= 1 << (i & 7); + } + if (i == '_') + p[cbit_word + i / 8] |= 1 << (i & 7); + if (isspace(i)) + p[cbit_space + i / 8] |= 1 << (i & 7); + if (isxdigit(i)) + p[cbit_xdigit + i / 8] |= 1 << (i & 7); + if (isgraph(i)) + p[cbit_graph + i / 8] |= 1 << (i & 7); + if (isprint(i)) + p[cbit_print + i / 8] |= 1 << (i & 7); + if (ispunct(i)) + p[cbit_punct + i / 8] |= 1 << (i & 7); + if (iscntrl(i)) + p[cbit_cntrl + i / 8] |= 1 << (i & 7); + } + p += cbit_length; + + for (i = 0; i < 256; i++) { + int x = 0; + if (isspace(i)) + x += ctype_space; + if (isalpha(i)) + x += ctype_letter; + if (isdigit(i)) + x += ctype_digit; + if (isxdigit(i)) + x += ctype_xdigit; + if (isalnum(i) || i == '_') + x += ctype_word; + if (strchr("*+?{^.$|()[", i) != 0) + x += ctype_meta; + *p++ = x; + } -for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); - -/* Then the character class tables. Don't try to be clever and save effort -on exclusive ones - in some locales things may be different. */ - -memset(p, 0, cbit_length); -for (i = 0; i < 256; i++) - { - if (isdigit(i)) - { - p[cbit_digit + i/8] |= 1 << (i&7); - p[cbit_word + i/8] |= 1 << (i&7); - } - if (isupper(i)) - { - p[cbit_upper + i/8] |= 1 << (i&7); - p[cbit_word + i/8] |= 1 << (i&7); - } - if (islower(i)) - { - p[cbit_lower + i/8] |= 1 << (i&7); - p[cbit_word + i/8] |= 1 << (i&7); - } - if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); - if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); - if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); - if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); - if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); - if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); - if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); - } -p += cbit_length; - -/* Finally, the character type table */ - -for (i = 0; i < 256; i++) - { - int x = 0; - if (isspace(i)) x += ctype_space; - if (isalpha(i)) x += ctype_letter; - if (isdigit(i)) x += ctype_digit; - if (isxdigit(i)) x += ctype_xdigit; - if (isalnum(i) || i == '_') x += ctype_word; - if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; - *p++ = x; - } - -return yield; + return yield; } -/* ____ END maketables.c ____ */ - -#ifdef STR_PCRE_GENTAB - -/* ____ BEGIN dftables.c ____ */ - -/* This is a support program to generate the file chartables.c, containing -character tables of various kinds. They are built according to the default C -locale and used as the default tables by PCRE. 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 STR_PCRE_TAB #include #include @@ -5757,94 +4199,78 @@ int main(void) { -int i; -const unsigned char *tables = pcre_maketables(); + int i; + const unsigned char *tables = pcre_maketables(); -printf( - "/*************************************************\n" - "* Perl-Compatible Regular Expressions *\n" - "*************************************************/\n\n" - "static unsigned char pcre_default_tables[] = {\n\n" - "/* This table is a lower casing table. */\n\n"); - -printf(" "); -for (i = 0; i < 256; i++) - { - if ((i & 7) == 0 && i != 0) printf("\n "); - printf("%3d", *tables++); - if (i != 255) printf(","); - } -printf(",\n\n"); - -printf("/* This table is a case flipping table. */\n\n"); - -printf(" "); -for (i = 0; i < 256; i++) - { - if ((i & 7) == 0 && i != 0) printf("\n "); - printf("%3d", *tables++); - if (i != 255) printf(","); - } -printf(",\n\n"); - -printf( - "/* This table contains bit maps for various character classes.\n" - "Each map is 32 bytes long and the bits run from the least\n" - "significant end of each byte. The classes that have their own\n" - "maps are: space, xdigit, digit, upper, lower, word, graph\n" - "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); - -printf(" "); -for (i = 0; i < cbit_length; i++) - { - if ((i & 7) == 0 && i != 0) - { - if ((i & 31) == 0) printf("\n"); - printf("\n "); - } - printf("0x%02x", *tables++); - if (i != cbit_length - 1) printf(","); - } -printf(",\n\n"); - -printf( - "/* This table identifies various classes of character by individual bits:\n" - " 0x%02x white space character\n" - " 0x%02x letter\n" - " 0x%02x decimal digit\n" - " 0x%02x hexadecimal digit\n" - " 0x%02x alphanumeric or '_'\n" - " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", - ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, - ctype_meta); - -printf(" "); -for (i = 0; i < 256; i++) - { - if ((i & 7) == 0 && i != 0) - { - printf(" /* "); - if (isprint(i-8)) printf(" %c -", i-8); - else printf("%3d-", i-8); - if (isprint(i-1)) printf(" %c ", i-1); - else printf("%3d", i-1); - printf(" */\n "); - } - printf("0x%02x", *tables++); - if (i != 255) printf(","); - } - -printf("};/* "); -if (isprint(i-8)) printf(" %c -", i-8); - else printf("%3d-", i-8); -if (isprint(i-1)) printf(" %c ", i-1); - else printf("%3d", i-1); -printf(" */\n\n\n"); + printf("/*************************************************\n" + "* Perl-Compatible Regular Expressions *\n" + "*************************************************/\n\n" + "static unsigned char pcre_default_tables[] = {\n\n" + "/* This table is a lower casing table. */\n\n"); + + printf(" "); + for (i = 0; i < 256; i++) { + if ((i & 7) == 0 && i != 0) + printf("\n "); + printf("%3d", *tables++); + if (i != 255) + printf(","); + } + printf(",\n\n"); + + printf("/* This table is a case flipping table. */\n\n"); + + printf(" "); + for (i = 0; i < 256; i++) { + if ((i & 7) == 0 && i != 0) + printf("\n "); + printf("%3d", *tables++); + if (i != 255) + printf(","); + } + printf(",\n\n"); + + printf("/* This table contains bit maps for various character classes.\n" + "Each map is 32 bytes long and the bits run from the least\n" + "significant end of each byte. The classes that have their own\n" + "maps are: space, xdigit, digit, upper, lower, word, graph\n" + "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); + + printf(" "); + for (i = 0; i < cbit_length; i++) { + if ((i & 7) == 0 && i != 0) { + if ((i & 31) == 0) + printf("\n"); + printf("\n "); + } + printf("0x%02x", *tables++); + if (i != cbit_length - 1) + printf(","); + } + printf(",\n\n"); + + printf + ("/* This table identifies various classes of character by individual bits:\n" + " 0x%02x white space character\n" " 0x%02x letter\n" + " 0x%02x decimal digit\n" " 0x%02x hexadecimal digit\n" + " 0x%02x alphanumeric or '_'\n" + " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", + ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, + ctype_meta); + + printf(" "); + for (i = 0; i < 256; i++) { + if ((i & 7) == 0 && i != 0) { + printf(" \n "); + } + printf("0x%02x", *tables++); + if (i != 255) + printf(","); + } -return 0; -} + printf("};\n\n\n"); -/* ____ END dftables.c ____ */ - -#endif /* STR_PCRE_GENTAB */ + return 0; +} +#endif Index: ossp-pkg/str/str_pcre.h RCS File: /v/ossp/cvs/ossp-pkg/str/str_pcre.h,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/str/str_pcre.h,v' 2>/dev/null --- str_pcre.h 2001/08/16 12:04:25 1.2 +++ str_pcre.h 2001/12/27 12:24:20 1.3 @@ -1,6 +1,16 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ +/* + * Perl Compatible Regular Expression (PCRE) Library + * Copyright (c) 1997-2001 Philip Hazel + * Copyright (c) 1997-2001 University of Cambridge + * + * DO NOT EDIT THIS FILE, IT WAS AUTOMATICALLY GENERATED! + * + * This is an automatically generated, extremely stripped down + * version of the PCRE 3.8 library from the Philip Hazel. + * This version is still distributed under the same original PCRE + * Open Source license, but Philip Hazel is no longer responsible + * for this version. + */ /* This is a library of functions to support regular expressions whose syntax @@ -35,26 +45,42 @@ #ifndef __STR_PCRE_H__ #define __STR_PCRE_H__ -/* The file pcre.h is build by "configure". Do not edit it; instead -make changes to pcre.in. */ +#define PCRE_PREFIX str_ #define PCRE_MAJOR 3 -#define PCRE_MINOR 5 -#define PCRE_DATE 15-Aug-2001 +#define PCRE_MINOR 8 +#define PCRE_DATE 18-Dec-2001 -/* Have to include stdlib.h in order to ensure that size_t is defined; -it is needed here for malloc. */ +#ifdef PCRE_PREFIX +#if defined(__STDC__) || defined(__cplusplus) +#define __PCRE_CONCAT(x,y) x ## y +#define PCRE_CONCAT(x,y) __PCRE_CONCAT(x,y) +#else +#define __PCRE_CONCAT(x) x +#define PCRE_CONCAT(x,y) __PCRE_CONCAT(x)y +#endif +#define pcre_malloc PCRE_CONCAT(PCRE_PREFIX,pcre_malloc) +#define pcre_free PCRE_CONCAT(PCRE_PREFIX,pcre_free) +#define pcre_compile PCRE_CONCAT(PCRE_PREFIX,pcre_compile) +#define pcre_copy_substring PCRE_CONCAT(PCRE_PREFIX,pcre_copy_substring) +#define pcre_exec PCRE_CONCAT(PCRE_PREFIX,pcre_exec) +#define pcre_free_substring PCRE_CONCAT(PCRE_PREFIX,pcre_free_substring) +#define pcre_free_substring_list PCRE_CONCAT(PCRE_PREFIX,pcre_free_substring_list) +#define pcre_get_substring PCRE_CONCAT(PCRE_PREFIX,pcre_get_substring) +#define pcre_get_substring_list PCRE_CONCAT(PCRE_PREFIX,pcre_get_substring_list) +#define pcre_info PCRE_CONCAT(PCRE_PREFIX,pcre_info) +#define pcre_fullinfo PCRE_CONCAT(PCRE_PREFIX,pcre_fullinfo) +#define pcre_maketables PCRE_CONCAT(PCRE_PREFIX,pcre_maketables) +#define pcre_study PCRE_CONCAT(PCRE_PREFIX,pcre_study) +#define pcre_version PCRE_CONCAT(PCRE_PREFIX,pcre_version) +#endif #include -/* Allow for C++ users */ - #ifdef __cplusplus extern "C" { #endif -/* Options */ - #define PCRE_CASELESS 0x0001 #define PCRE_MULTILINE 0x0002 #define PCRE_DOTALL 0x0004 @@ -68,8 +94,6 @@ #define PCRE_NOTEMPTY 0x0400 #define PCRE_UTF8 0x0800 -/* Exec-time and get-time error codes */ - #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) @@ -78,8 +102,6 @@ #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) -/* Request types for pcre_fullinfo() */ - #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 @@ -88,23 +110,15 @@ #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 -/* Types */ - -struct real_pcre; /* declaration; the definition is private */ -struct real_pcre_extra; /* declaration; the definition is private */ - -typedef struct real_pcre pcre; -typedef struct real_pcre_extra pcre_extra; +struct pcre_st; +struct pcre_extra_st; -/* Store get and free functions. These can be set to alternative malloc/free -functions if required. Some magic is required for Win32 DLL; it is null on -other OS. */ +typedef struct pcre_st pcre; +typedef struct pcre_extra_st pcre_extra; extern void *(*pcre_malloc)(size_t); extern void (*pcre_free)(void *); -/* Functions */ - extern pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); extern int pcre_copy_substring(const char *, int *, int, int, char *, int); @@ -121,7 +135,7 @@ extern const char *pcre_version(void); #ifdef __cplusplus -} /* extern "C" */ +} #endif -#endif /* __STR_PCRE_H__ */ +#endif