[exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog pcre…

Top Pagina
Delete this message
Reply to this message
Auteur: Philip Hazel
Datum:  
Aan: exim-cvs
Onderwerp: [exim-cvs] cvs commit: exim/exim-doc/doc-txt ChangeLog pcrepattern.txt pcretest.txt exim/exim-src/scripts MakeLinks exim/exim-src/src/pcre ChangeLog LICENCE Makefile config.h dftables.c get.c inter
ph10 2006/11/07 16:50:37 GMT

  Modified files:
    exim-doc/doc-txt     ChangeLog pcrepattern.txt pcretest.txt 
    exim-src/scripts     MakeLinks 
    exim-src/src/pcre    ChangeLog LICENCE Makefile config.h 
                         dftables.c pcre.h pcre_compile.c 
                         pcre_config.c pcre_exec.c pcre_fullinfo.c 
                         pcre_get.c pcre_globals.c pcre_internal.h 
                         pcre_maketables.c pcre_printint.c 
                         pcre_study.c pcre_tables.c 
                         pcre_try_flipped.c pcre_version.c 
                         pcretest.c ucp.h 
  Added files:
    exim-src/src/pcre    pcre_printint.src 
  Removed files:
    exim-src/src/pcre    get.c internal.h maketables.c pcre.c 
                         printint.c study.c 
  Log:
  Install PCRE 6.7 in in place of 6.2.


  Revision  Changes    Path
  1.429     +3 -0      exim/exim-doc/doc-txt/ChangeLog
  1.4       +300 -198  exim/exim-doc/doc-txt/pcrepattern.txt
  1.4       +185 -145  exim/exim-doc/doc-txt/pcretest.txt
  1.9       +1 -1      exim/exim-src/scripts/MakeLinks
  1.4       +453 -0    exim/exim-src/src/pcre/ChangeLog
  1.3       +2 -2      exim/exim-src/src/pcre/LICENCE
  1.6       +1 -5      exim/exim-src/src/pcre/Makefile
  1.2       +10 -5     exim/exim-src/src/pcre/config.h
  1.4       +1 -1      exim/exim-src/src/pcre/dftables.c
  1.3       +0 -359    exim/exim-src/src/pcre/get.c (dead)
  1.3       +0 -754    exim/exim-src/src/pcre/internal.h (dead)
  1.3       +0 -148    exim/exim-src/src/pcre/maketables.c (dead)
  1.3       +0 -9196   exim/exim-src/src/pcre/pcre.c (dead)
  1.4       +50 -16    exim/exim-src/src/pcre/pcre.h
  1.3       +506 -283  exim/exim-src/src/pcre/pcre_compile.c
  1.3       +6 -2      exim/exim-src/src/pcre/pcre_config.c
  1.3       +663 -362  exim/exim-src/src/pcre/pcre_exec.c
  1.3       +2 -2      exim/exim-src/src/pcre/pcre_fullinfo.c
  1.3       +117 -7    exim/exim-src/src/pcre/pcre_get.c
  1.3       +1 -1      exim/exim-src/src/pcre/pcre_globals.c
  1.3       +98 -53    exim/exim-src/src/pcre/pcre_internal.h
  1.3       +16 -21    exim/exim-src/src/pcre/pcre_maketables.c
  1.3       +0 -451    exim/exim-src/src/pcre/pcre_printint.c
  1.1       +462 -0    exim/exim-src/src/pcre/pcre_printint.src (new)
  1.3       +52 -9     exim/exim-src/src/pcre/pcre_study.c
  1.3       +107 -43   exim/exim-src/src/pcre/pcre_tables.c
  1.3       +4 -4      exim/exim-src/src/pcre/pcre_try_flipped.c
  1.3       +6 -3      exim/exim-src/src/pcre/pcre_version.c
  1.4       +457 -108  exim/exim-src/src/pcre/pcretest.c
  1.3       +0 -467    exim/exim-src/src/pcre/printint.c (dead)
  1.3       +0 -486    exim/exim-src/src/pcre/study.c (dead)
  1.3       +71 -5     exim/exim-src/src/pcre/ucp.h


  Index: ChangeLog
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
  retrieving revision 1.428
  retrieving revision 1.429
  diff -u -r1.428 -r1.429
  --- ChangeLog    7 Nov 2006 15:56:17 -0000    1.428
  +++ ChangeLog    7 Nov 2006 16:50:36 -0000    1.429
  @@ -1,10 +1,11 @@
  -$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.428 2006/11/07 15:56:17 ph10 Exp $
  +$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.429 2006/11/07 16:50:36 ph10 Exp $


Change log file for Exim from version 4.21
-------------------------------------------

   Exim version 4.64
   -----------------
  +
   TK/01 Bugzilla #401. Fix DK spooling code so that it can overwrite a
         leftover -K file (the existence of which was triggered by #402).
         While we were at it, introduced process PID as part of the -K
  @@ -258,6 +259,8 @@
   PH/39 If -R or -S was given with -q<time>, the effect of -R or -S was ignored,
         and queue runs started by the daemon processed all messages. This has
         been fixed so that -R and -S can now usefully be given with -q<time>.
  +
  +PH/40 Import PCRE release 6.7 (fixes some bugs).



Exim version 4.63

  Index: pcrepattern.txt
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/pcrepattern.txt,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- pcrepattern.txt    8 Aug 2005 10:22:14 -0000    1.3
  +++ pcrepattern.txt    7 Nov 2006 16:50:36 -0000    1.4
  @@ -1,5 +1,5 @@
   This file contains the PCRE man page that describes the regular expressions
  -supported by PCRE version 6.2. Note that not all of the features are relevant
  +supported by PCRE version 6.7. Note that not all of the features are relevant
   in the context of Exim. In particular, the version of PCRE that is compiled
   with Exim does not include UTF-8 support, there is no mechanism for changing
   the options with which the PCRE functions are called, and features such as
  @@ -110,9 +110,9 @@


          If  a  pattern is compiled with the PCRE_EXTENDED option, whitespace in
          the pattern (other than in a character class) and characters between  a
  -       # outside a character class and the next newline character are ignored.
  -       An escaping backslash can be used to include a whitespace or #  charac-
  -       ter as part of the pattern.
  +       # outside a character class and the next newline are ignored. An escap-
  +       ing backslash can be used to include a whitespace  or  #  character  as
  +       part of the pattern.


          If  you  want  to remove the special meaning from a sequence of charac-
          ters, you can do so by putting them between \Q and \E. This is  differ-
  @@ -148,7 +148,7 @@
            \t        tab (hex 09)
            \ddd      character with octal code ddd, or backreference
            \xhh      character with hex code hh
  -         \x{hhh..} character with hex code hhh... (UTF-8 mode only)
  +         \x{hhh..} character with hex code hhh..


          The  precise  effect of \cx is as follows: if x is a lower case letter,
          it is converted to upper case. Then bit 6 of the character (hex 40)  is
  @@ -156,26 +156,24 @@
          becomes hex 7B.


          After \x, from zero to two hexadecimal digits are read (letters can  be
  -       in  upper or lower case). In UTF-8 mode, any number of hexadecimal dig-
  -       its may appear between \x{ and }, but the value of the  character  code
  -       must  be  less  than  2**31  (that is, the maximum hexadecimal value is
  -       7FFFFFFF). If characters other than hexadecimal digits  appear  between
  -       \x{  and }, or if there is no terminating }, this form of escape is not
  -       recognized. Instead, the initial \x will  be  interpreted  as  a  basic
  -       hexadecimal  escape, with no following digits, giving a character whose
  -       value is zero.
  +       in  upper  or  lower case). Any number of hexadecimal digits may appear
  +       between \x{ and }, but the value of the character  code  must  be  less
  +       than 256 in non-UTF-8 mode, and less than 2**31 in UTF-8 mode (that is,
  +       the maximum hexadecimal value is 7FFFFFFF). If  characters  other  than
  +       hexadecimal  digits  appear between \x{ and }, or if there is no termi-
  +       nating }, this form of escape is not recognized.  Instead, the  initial
  +       \x will be interpreted as a basic hexadecimal escape, with no following
  +       digits, giving a character whose value is zero.


          Characters whose value is less than 256 can be defined by either of the
  -       two  syntaxes for \x when PCRE is in UTF-8 mode. There is no difference
  -       in the way they are handled. For example, \xdc is exactly the  same  as
  -       \x{dc}.
  -
  -       After  \0  up  to  two further octal digits are read. In both cases, if
  -       there are fewer than two digits, just those that are present are  used.
  -       Thus  the sequence \0\x\07 specifies two binary zeros followed by a BEL
  -       character (code value 7). Make sure you supply  two  digits  after  the
  -       initial  zero  if the pattern character that follows is itself an octal
  -       digit.
  +       two  syntaxes  for  \x. There is no difference in the way they are han-
  +       dled. For example, \xdc is exactly the same as \x{dc}.
  +
  +       After \0 up to two further octal digits are read. If  there  are  fewer
  +       than  two  digits,  just  those  that  are  present  are used. Thus the
  +       sequence \0\x\07 specifies two binary zeros followed by a BEL character
  +       (code  value 7). Make sure you supply two digits after the initial zero
  +       if the pattern character that follows is itself an octal digit.


          The handling of a backslash followed by a digit other than 0 is compli-
          cated.  Outside a character class, PCRE reads it and any following dig-
  @@ -187,9 +185,11 @@


          Inside a character class, or if the decimal number is  greater  than  9
          and  there have not been that many capturing subpatterns, PCRE re-reads
  -       up to three octal digits following the backslash, and generates a  sin-
  -       gle byte from the least significant 8 bits of the value. Any subsequent
  -       digits stand for themselves.  For example:
  +       up to three octal digits following the backslash, ane uses them to gen-
  +       erate  a data character. Any subsequent digits stand for themselves. In
  +       non-UTF-8 mode, the value of a character specified  in  octal  must  be
  +       less  than  \400.  In  UTF-8 mode, values up to \777 are permitted. For
  +       example:


            \040   is another way of writing a space
            \40    is the same, provided there are fewer than 40
  @@ -209,16 +209,15 @@
          Note that octal values of 100 or greater must not be  introduced  by  a
          leading zero, because no more than three octal digits are ever read.


  -       All  the  sequences  that  define a single byte value or a single UTF-8
  -       character (in UTF-8 mode) can be used both inside and outside character
  -       classes.  In  addition,  inside  a  character class, the sequence \b is
  -       interpreted as the backspace character (hex 08), and the sequence \X is
  -       interpreted  as  the  character  "X".  Outside a character class, these
  -       sequences have different meanings (see below).
  +       All the sequences that define a single character value can be used both
  +       inside and outside character classes. In addition, inside  a  character
  +       class,  the  sequence \b is interpreted as the backspace character (hex
  +       08), and the sequence \X is interpreted as the character "X". Outside a
  +       character class, these sequences have different meanings (see below).


      Generic character types


  -       The third use of backslash is for specifying generic  character  types.
  +       The  third  use of backslash is for specifying generic character types.
          The following are always recognized:


            \d     any decimal digit
  @@ -229,56 +228,83 @@
            \W     any "non-word" character


          Each pair of escape sequences partitions the complete set of characters
  -       into two disjoint sets. Any given character matches one, and only  one,
  +       into  two disjoint sets. Any given character matches one, and only one,
          of each pair.


          These character type sequences can appear both inside and outside char-
  -       acter classes. They each match one character of the  appropriate  type.
  -       If  the current matching point is at the end of the subject string, all
  +       acter  classes.  They each match one character of the appropriate type.
  +       If the current matching point is at the end of the subject string,  all
          of them fail, since there is no character to match.


  -       For compatibility with Perl, \s does not match the VT  character  (code
  -       11).   This makes it different from the the POSIX "space" class. The \s
  -       characters are HT (9), LF (10), FF (12), CR (13), and space (32).
  +       For  compatibility  with Perl, \s does not match the VT character (code
  +       11).  This makes it different from the the POSIX "space" class. The  \s
  +       characters  are  HT (9), LF (10), FF (12), CR (13), and space (32). (If
  +       "use locale;" is included in a Perl script, \s may match the VT charac-
  +       ter. In PCRE, it never does.)


          A "word" character is an underscore or any character less than 256 that
  -       is  a  letter  or  digit.  The definition of letters and digits is con-
  -       trolled by PCRE's low-valued character tables, and may vary if  locale-
  -       specific  matching is taking place (see "Locale support" in the pcreapi
  -       page). For example, in the  "fr_FR"  (French)  locale,  some  character
  -       codes  greater  than  128  are used for accented letters, and these are
  +       is a letter or digit. The definition of  letters  and  digits  is  con-
  +       trolled  by PCRE's low-valued character tables, and may vary if locale-
  +       specific matching is taking place (see "Locale support" in the  pcreapi
  +       page).  For  example,  in  the  "fr_FR" (French) locale, some character
  +       codes greater than 128 are used for accented  letters,  and  these  are
          matched by \w.


  -       In UTF-8 mode, characters with values greater than 128 never match  \d,
  +       In  UTF-8 mode, characters with values greater than 128 never match \d,
          \s, or \w, and always match \D, \S, and \W. This is true even when Uni-
  -       code character property support is available.
  +       code  character  property support is available. The use of locales with
  +       Unicode is discouraged.


      Unicode character properties


          When PCRE is built with Unicode character property support, three addi-
  -       tional  escape sequences to match generic character types are available
  +       tional  escape  sequences  to  match character properties are available
          when UTF-8 mode is selected. They are:


  -        \p{xx}   a character with the xx property
  -        \P{xx}   a character without the xx property
  -        \X       an extended Unicode sequence
  +         \p{xx}   a character with the xx property
  +         \P{xx}   a character without the xx property
  +         \X       an extended Unicode sequence


          The property names represented by xx above are limited to  the  Unicode
  -       general  category properties. Each character has exactly one such prop-
  -       erty, specified by a two-letter abbreviation.  For  compatibility  with
  -       Perl,  negation  can be specified by including a circumflex between the
  -       opening brace and the property name. For example, \p{^Lu} is  the  same
  -       as \P{Lu}.
  -
  -       If  only  one  letter  is  specified with \p or \P, it includes all the
  -       properties that start with that letter. In this case, in the absence of
  -       negation, the curly brackets in the escape sequence are optional; these
  -       two examples have the same effect:
  +       script names, the general category properties, and "Any", which matches
  +       any character (including newline). Other properties such as "InMusical-
  +       Symbols"  are  not  currently supported by PCRE. Note that \P{Any} does
  +       not match any characters, so always causes a match failure.
  +
  +       Sets of Unicode characters are defined as belonging to certain scripts.
  +       A  character from one of these sets can be matched using a script name.
  +       For example:
  +
  +         \p{Greek}
  +         \P{Han}
  +
  +       Those that are not part of an identified script are lumped together  as
  +       "Common". The current list of scripts is:
  +
  +       Arabic,  Armenian,  Bengali,  Bopomofo, Braille, Buginese, Buhid, Cana-
  +       dian_Aboriginal, Cherokee, Common, Coptic, Cypriot, Cyrillic,  Deseret,
  +       Devanagari,  Ethiopic,  Georgian,  Glagolitic, Gothic, Greek, Gujarati,
  +       Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana,  Inherited,  Kannada,
  +       Katakana,  Kharoshthi,  Khmer,  Lao, Latin, Limbu, Linear_B, Malayalam,
  +       Mongolian, Myanmar, New_Tai_Lue, Ogham, Old_Italic, Old_Persian, Oriya,
  +       Osmanya,  Runic,  Shavian, Sinhala, Syloti_Nagri, Syriac, Tagalog, Tag-
  +       banwa,  Tai_Le,  Tamil,  Telugu,  Thaana,  Thai,   Tibetan,   Tifinagh,
  +       Ugaritic, Yi.
  +
  +       Each  character has exactly one general category property, specified by
  +       a two-letter abbreviation. For compatibility with Perl, negation can be
  +       specified  by  including a circumflex between the opening brace and the
  +       property name. For example, \p{^Lu} is the same as \P{Lu}.
  +
  +       If only one letter is specified with \p or \P, it includes all the gen-
  +       eral  category properties that start with that letter. In this case, in
  +       the absence of negation, the curly brackets in the escape sequence  are
  +       optional; these two examples have the same effect:


            \p{L}
            \pL


  -       The following property codes are supported:
  +       The following general category property codes are supported:


            C     Other
            Cc    Control
  @@ -324,8 +350,17 @@
            Zp    Paragraph separator
            Zs    Space separator


  -       Extended properties such as "Greek" or "InMusicalSymbols" are not  sup-
  -       ported by PCRE.
  +       The  special property L& is also supported: it matches a character that
  +       has the Lu, Ll, or Lt property, in other words, a letter  that  is  not
  +       classified as a modifier or "other".
  +
  +       The  long  synonyms  for  these  properties that Perl supports (such as
  +       \p{Letter}) are not supported by PCRE, nor is it  permitted  to  prefix
  +       any of these properties with "Is".
  +
  +       No character that is in the Unicode table has the Cn (unassigned) prop-
  +       erty.  Instead, this property is assumed for any code point that is not
  +       in the Unicode table.


          Specifying  caseless  matching  does not affect these escape sequences.
          For example, \p{Lu} always matches only upper case letters.
  @@ -378,24 +413,23 @@
          However, if the startoffset argument of pcre_exec() is non-zero,  indi-
          cating that matching is to start at a point other than the beginning of
          the subject, \A can never match. The difference between \Z  and  \z  is
  -       that  \Z  matches  before  a  newline that is the last character of the
  -       string as well as at the end of the string, whereas \z matches only  at
  -       the end.
  -
  -       The  \G assertion is true only when the current matching position is at
  -       the start point of the match, as specified by the startoffset  argument
  -       of  pcre_exec().  It  differs  from \A when the value of startoffset is
  -       non-zero. By calling pcre_exec() multiple times with appropriate  argu-
  +       that \Z matches before a newline at the end of the string as well as at
  +       the very end, whereas \z matches only at the end.
  +
  +       The \G assertion is true only when the current matching position is  at
  +       the  start point of the match, as specified by the startoffset argument
  +       of pcre_exec(). It differs from \A when the  value  of  startoffset  is
  +       non-zero.  By calling pcre_exec() multiple times with appropriate argu-
          ments, you can mimic Perl's /g option, and it is in this kind of imple-
          mentation where \G can be useful.


  -       Note, however, that PCRE's interpretation of \G, as the  start  of  the
  +       Note,  however,  that  PCRE's interpretation of \G, as the start of the
          current match, is subtly different from Perl's, which defines it as the
  -       end of the previous match. In Perl, these can  be  different  when  the
  -       previously  matched  string was empty. Because PCRE does just one match
  +       end  of  the  previous  match. In Perl, these can be different when the
  +       previously matched string was empty. Because PCRE does just  one  match
          at a time, it cannot reproduce this behaviour.


  -       If all the alternatives of a pattern begin with \G, the  expression  is
  +       If  all  the alternatives of a pattern begin with \G, the expression is
          anchored to the starting match position, and the "anchored" flag is set
          in the compiled regular expression.


@@ -403,68 +437,81 @@
CIRCUMFLEX AND DOLLAR

          Outside a character class, in the default matching mode, the circumflex
  -       character  is  an  assertion  that is true only if the current matching
  -       point is at the start of the subject string. If the  startoffset  argu-
  -       ment  of  pcre_exec()  is  non-zero,  circumflex can never match if the
  -       PCRE_MULTILINE option is unset. Inside a  character  class,  circumflex
  +       character is an assertion that is true only  if  the  current  matching
  +       point  is  at the start of the subject string. If the startoffset argu-
  +       ment of pcre_exec() is non-zero, circumflex  can  never  match  if  the
  +       PCRE_MULTILINE  option  is  unset. Inside a character class, circumflex
          has an entirely different meaning (see below).


  -       Circumflex  need  not be the first character of the pattern if a number
  -       of alternatives are involved, but it should be the first thing in  each
  -       alternative  in  which  it appears if the pattern is ever to match that
  -       branch. If all possible alternatives start with a circumflex, that  is,
  -       if  the  pattern  is constrained to match only at the start of the sub-
  -       ject, it is said to be an "anchored" pattern.  (There  are  also  other
  +       Circumflex need not be the first character of the pattern if  a  number
  +       of  alternatives are involved, but it should be the first thing in each
  +       alternative in which it appears if the pattern is ever  to  match  that
  +       branch.  If all possible alternatives start with a circumflex, that is,
  +       if the pattern is constrained to match only at the start  of  the  sub-
  +       ject,  it  is  said  to be an "anchored" pattern. (There are also other
          constructs that can cause a pattern to be anchored.)


  -       A  dollar  character  is  an assertion that is true only if the current
  -       matching point is at the end of  the  subject  string,  or  immediately
  -       before a newline character that is the last character in the string (by
  -       default). Dollar need not be the last character of  the  pattern  if  a
  -       number  of alternatives are involved, but it should be the last item in
  -       any branch in which it appears.  Dollar has no  special  meaning  in  a
  -       character class.
  +       A dollar character is an assertion that is true  only  if  the  current
  +       matching  point  is  at  the  end of the subject string, or immediately
  +       before a newline at the end of the string (by default). Dollar need not
  +       be  the  last  character of the pattern if a number of alternatives are
  +       involved, but it should be the last item in  any  branch  in  which  it
  +       appears. Dollar has no special meaning in a character class.


          The  meaning  of  dollar  can be changed so that it matches only at the
          very end of the string, by setting the  PCRE_DOLLAR_ENDONLY  option  at
          compile time. This does not affect the \Z assertion.


          The meanings of the circumflex and dollar characters are changed if the
  -       PCRE_MULTILINE option is set. When this is the case, they match immedi-
  -       ately  after  and  immediately  before  an  internal newline character,
  -       respectively, in addition to matching at the start and end of the  sub-
  -       ject  string.  For  example,  the  pattern  /^abc$/ matches the subject
  -       string "def\nabc" (where \n represents a newline character)  in  multi-
  -       line mode, but not otherwise.  Consequently, patterns that are anchored
  -       in single line mode because all branches start with ^ are not  anchored
  -       in  multiline  mode,  and  a  match for circumflex is possible when the
  -       startoffset  argument  of  pcre_exec()  is  non-zero.   The   PCRE_DOL-
  -       LAR_ENDONLY option is ignored if PCRE_MULTILINE is set.
  -
  -       Note  that  the sequences \A, \Z, and \z can be used to match the start
  -       and end of the subject in both modes, and if all branches of a  pattern
  -       start  with  \A it is always anchored, whether PCRE_MULTILINE is set or
  -       not.
  +       PCRE_MULTILINE option is set. When  this  is  the  case,  a  circumflex
  +       matches  immediately after internal newlines as well as at the start of
  +       the subject string. It does not match after a  newline  that  ends  the
  +       string.  A dollar matches before any newlines in the string, as well as
  +       at the very end, when PCRE_MULTILINE is set. When newline is  specified
  +       as  the  two-character  sequence CRLF, isolated CR and LF characters do
  +       not indicate newlines.
  +
  +       For example, the pattern /^abc$/ matches the subject string  "def\nabc"
  +       (where  \n  represents a newline) in multiline mode, but not otherwise.
  +       Consequently, patterns that are anchored in single  line  mode  because
  +       all  branches  start  with  ^ are not anchored in multiline mode, and a
  +       match for circumflex is  possible  when  the  startoffset  argument  of
  +       pcre_exec()  is  non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if
  +       PCRE_MULTILINE is set.
  +
  +       Note that the sequences \A, \Z, and \z can be used to match  the  start
  +       and  end of the subject in both modes, and if all branches of a pattern
  +       start with \A it is always anchored, whether or not  PCRE_MULTILINE  is
  +       set.



FULL STOP (PERIOD, DOT)

          Outside a character class, a dot in the pattern matches any one charac-
  -       ter  in  the  subject,  including a non-printing character, but not (by
  -       default) newline.  In UTF-8 mode, a dot matches  any  UTF-8  character,
  -       which might be more than one byte long, except (by default) newline. If
  -       the PCRE_DOTALL option is set, dots match newlines as  well.  The  han-
  -       dling  of dot is entirely independent of the handling of circumflex and
  -       dollar, the only relationship being  that  they  both  involve  newline
  -       characters. Dot has no special meaning in a character class.
  +       ter in the subject string except (by default) a character  that  signi-
  +       fies  the  end  of  a line. In UTF-8 mode, the matched character may be
  +       more than one byte long. When a line ending  is  defined  as  a  single
  +       character  (CR  or LF), dot never matches that character; when the two-
  +       character sequence CRLF is used, dot does not match CR if it is immedi-
  +       ately  followed by LF, but otherwise it matches all characters (includ-
  +       ing isolated CRs and LFs).
  +
  +       The behaviour of dot with regard to newlines can  be  changed.  If  the
  +       PCRE_DOTALL  option  is  set,  a dot matches any one character, without
  +       exception. If newline is defined as the two-character sequence CRLF, it
  +       takes two dots to match it.
  +
  +       The  handling of dot is entirely independent of the handling of circum-
  +       flex and dollar, the only relationship being  that  they  both  involve
  +       newlines. Dot has no special meaning in a character class.



MATCHING A SINGLE BYTE

          Outside a character class, the escape sequence \C matches any one byte,
  -       both in and out of UTF-8 mode. Unlike a dot, it can  match  a  newline.
  -       The  feature  is provided in Perl in order to match individual bytes in
  -       UTF-8 mode. Because it  breaks  up  UTF-8  characters  into  individual
  +       both in and out of UTF-8 mode. Unlike a dot, it always matches  CR  and
  +       LF.  The feature is provided in Perl in order to match individual bytes
  +       in UTF-8 mode.  Because it breaks up UTF-8 characters  into  individual
          bytes,  what remains in the string may be a malformed UTF-8 string. For
          this reason, the \C escape sequence is best avoided.


  @@ -513,9 +560,11 @@
          PCRE  is  compiled  with Unicode property support as well as with UTF-8
          support.


  -       The newline character is never treated in any special way in  character
  -       classes,  whatever  the  setting  of  the PCRE_DOTALL or PCRE_MULTILINE
  -       options is. A class such as [^a] will always match a newline.
  +       Characters that might indicate  line  breaks  (CR  and  LF)  are  never
  +       treated  in  any  special way when matching character classes, whatever
  +       line-ending sequence is in use, and whatever setting of the PCRE_DOTALL
  +       and PCRE_MULTILINE options is used. A class such as [^a] always matches
  +       one of these characters.


          The minus (hyphen) character can be used to specify a range of  charac-
          ters  in  a  character  class.  For  example,  [d-m] matches any letter
  @@ -616,11 +665,10 @@


          matches  either "gilbert" or "sullivan". Any number of alternatives may
          appear, and an empty  alternative  is  permitted  (matching  the  empty
  -       string).   The  matching  process  tries each alternative in turn, from
  -       left to right, and the first one that succeeds is used. If the alterna-
  -       tives  are within a subpattern (defined below), "succeeds" means match-
  -       ing the rest of the main pattern as well as the alternative in the sub-
  -       pattern.
  +       string). The matching process tries each alternative in turn, from left
  +       to right, and the first one that succeeds is used. If the  alternatives
  +       are  within a subpattern (defined below), "succeeds" means matching the
  +       rest of the main pattern as well as the alternative in the  subpattern.



   INTERNAL OPTION SETTING
  @@ -666,12 +714,9 @@
          the effects of option settings happen at compile time. There  would  be
          some very weird behaviour otherwise.


  -       The  PCRE-specific  options PCRE_UNGREEDY and PCRE_EXTRA can be changed
  -       in the same way as the Perl-compatible options by using the  characters
  -       U  and X respectively. The (?X) flag setting is special in that it must
  -       always occur earlier in the pattern than any of the additional features
  -       it  turns on, even when it is at top level. It is best to put it at the
  -       start.
  +       The  PCRE-specific options PCRE_DUPNAMES, PCRE_UNGREEDY, and PCRE_EXTRA
  +       can be changed in the same way as the Perl-compatible options by  using
  +       the characters J, U and X respectively.



SUBPATTERNS
@@ -683,18 +728,18 @@

            cat(aract|erpillar|)


  -       matches  one  of the words "cat", "cataract", or "caterpillar". Without
  -       the parentheses, it would match "cataract",  "erpillar"  or  the  empty
  +       matches one of the words "cat", "cataract", or  "caterpillar".  Without
  +       the  parentheses,  it  would  match "cataract", "erpillar" or the empty
          string.


  -       2.  It  sets  up  the  subpattern as a capturing subpattern. This means
  -       that, when the whole pattern  matches,  that  portion  of  the  subject
  +       2. It sets up the subpattern as  a  capturing  subpattern.  This  means
  +       that,  when  the  whole  pattern  matches,  that portion of the subject
          string that matched the subpattern is passed back to the caller via the
  -       ovector argument of pcre_exec(). Opening parentheses are  counted  from
  -       left  to  right  (starting  from 1) to obtain numbers for the capturing
  +       ovector  argument  of pcre_exec(). Opening parentheses are counted from
  +       left to right (starting from 1) to obtain  numbers  for  the  capturing
          subpatterns.


  -       For example, if the string "the red king" is matched against  the  pat-
  +       For  example,  if the string "the red king" is matched against the pat-
          tern


            the ((red|white) (king|queen))
  @@ -702,50 +747,75 @@
          the captured substrings are "red king", "red", and "king", and are num-
          bered 1, 2, and 3, respectively.


  -       The fact that plain parentheses fulfil  two  functions  is  not  always
  -       helpful.   There are often times when a grouping subpattern is required
  -       without a capturing requirement. If an opening parenthesis is  followed
  -       by  a question mark and a colon, the subpattern does not do any captur-
  -       ing, and is not counted when computing the  number  of  any  subsequent
  -       capturing  subpatterns. For example, if the string "the white queen" is
  +       The  fact  that  plain  parentheses  fulfil two functions is not always
  +       helpful.  There are often times when a grouping subpattern is  required
  +       without  a capturing requirement. If an opening parenthesis is followed
  +       by a question mark and a colon, the subpattern does not do any  captur-
  +       ing,  and  is  not  counted when computing the number of any subsequent
  +       capturing subpatterns. For example, if the string "the white queen"  is
          matched against the pattern


            the ((?:red|white) (king|queen))


          the captured substrings are "white queen" and "queen", and are numbered
  -       1  and 2. The maximum number of capturing subpatterns is 65535, and the
  -       maximum depth of nesting of all subpatterns, both  capturing  and  non-
  +       1 and 2. The maximum number of capturing subpatterns is 65535, and  the
  +       maximum  depth  of  nesting of all subpatterns, both capturing and non-
          capturing, is 200.


  -       As  a  convenient shorthand, if any option settings are required at the
  -       start of a non-capturing subpattern,  the  option  letters  may  appear
  +       As a convenient shorthand, if any option settings are required  at  the
  +       start  of  a  non-capturing  subpattern,  the option letters may appear
          between the "?" and the ":". Thus the two patterns


            (?i:saturday|sunday)
            (?:(?i)saturday|sunday)


          match exactly the same set of strings. Because alternative branches are
  -       tried from left to right, and options are not reset until  the  end  of
  -       the  subpattern is reached, an option setting in one branch does affect
  -       subsequent branches, so the above patterns match "SUNDAY"  as  well  as
  +       tried  from  left  to right, and options are not reset until the end of
  +       the subpattern is reached, an option setting in one branch does  affect
  +       subsequent  branches,  so  the above patterns match "SUNDAY" as well as
          "Saturday".



NAMED SUBPATTERNS

  -       Identifying  capturing  parentheses  by number is simple, but it can be
  -       very hard to keep track of the numbers in complicated  regular  expres-
  -       sions.  Furthermore,  if  an  expression  is  modified, the numbers may
  -       change. To help with this difficulty, PCRE supports the naming of  sub-
  -       patterns,  something  that  Perl  does  not  provide. The Python syntax
  -       (?P<name>...) is used. Names consist  of  alphanumeric  characters  and
  -       underscores, and must be unique within a pattern.
  +       Identifying capturing parentheses by number is simple, but  it  can  be
  +       very  hard  to keep track of the numbers in complicated regular expres-
  +       sions. Furthermore, if an  expression  is  modified,  the  numbers  may
  +       change.  To help with this difficulty, PCRE supports the naming of sub-
  +       patterns, something that Perl  does  not  provide.  The  Python  syntax
  +       (?P<name>...)  is  used. References to capturing parentheses from other
  +       parts of the pattern, such as  backreferences,  recursion,  and  condi-
  +       tions, can be made by name as well as by number.


  -       Named  capturing  parentheses  are  still  allocated numbers as well as
  +       Names  consist  of  up  to  32 alphanumeric characters and underscores.
  +       Named capturing parentheses are still  allocated  numbers  as  well  as
          names. The PCRE API provides function calls for extracting the name-to-
  -       number  translation table from a compiled pattern. There is also a con-
  -       venience function for extracting a captured substring by name. For fur-
  -       ther details see the pcreapi documentation.
  +       number translation table from a compiled pattern. There is also a  con-
  +       venience function for extracting a captured substring by name.
  +
  +       By  default, a name must be unique within a pattern, but it is possible
  +       to relax this constraint by setting the PCRE_DUPNAMES option at compile
  +       time.  This  can  be useful for patterns where only one instance of the
  +       named parentheses can match. Suppose you want to match the  name  of  a
  +       weekday,  either as a 3-letter abbreviation or as the full name, and in
  +       both cases you want to extract the abbreviation. This pattern (ignoring
  +       the line breaks) does the job:
  +
  +         (?P<DN>Mon|Fri|Sun)(?:day)?|
  +         (?P<DN>Tue)(?:sday)?|
  +         (?P<DN>Wed)(?:nesday)?|
  +         (?P<DN>Thu)(?:rsday)?|
  +         (?P<DN>Sat)(?:urday)?
  +
  +       There  are  five capturing substrings, but only one is ever set after a
  +       match.  The convenience  function  for  extracting  the  data  by  name
  +       returns  the  substring  for  the first, and in this example, the only,
  +       subpattern of that name that matched.  This  saves  searching  to  find
  +       which  numbered  subpattern  it  was. If you make a reference to a non-
  +       unique named subpattern from elsewhere in the  pattern,  the  one  that
  +       corresponds  to  the  lowest number is used. For further details of the
  +       interfaces for handling named subpatterns, see the  pcreapi  documenta-
  +       tion.



   REPETITION
  @@ -954,8 +1024,10 @@
          meaning  or  processing  of  a possessive quantifier and the equivalent
          atomic group.


  -       The possessive quantifier syntax is an extension to the Perl syntax. It
  -       originates in Sun's Java package.
  +       The possessive quantifier syntax is an extension to  the  Perl  syntax.
  +       Jeffrey  Friedl originated the idea (and the name) in the first edition
  +       of his book.  Mike McCloskey liked it, so implemented it when he  built
  +       Sun's Java package, and PCRE copied it from there.


          When  a  pattern  contains an unlimited repeat inside a subpattern that
          can itself be repeated an unlimited number of  times,  the  use  of  an
  @@ -996,31 +1068,41 @@
          it  is  always  taken  as a back reference, and causes an error only if
          there are not that many capturing left parentheses in the  entire  pat-
          tern.  In  other words, the parentheses that are referenced need not be
  -       to the left of the reference for numbers less than 10. See the  subsec-
  -       tion  entitled  "Non-printing  characters" above for further details of
  -       the handling of digits following a backslash.
  +       to the left of the reference for numbers less than 10. A "forward  back
  +       reference"  of  this  type can make sense when a repetition is involved
  +       and the subpattern to the right has participated in an  earlier  itera-
  +       tion.


  -       A back reference matches whatever actually matched the  capturing  sub-
  -       pattern  in  the  current subject string, rather than anything matching
  +       It is not possible to have a numerical "forward back reference" to sub-
  +       pattern whose number is 10 or more. However, a back  reference  to  any
  +       subpattern  is  possible  using named parentheses (see below). See also
  +       the subsection entitled "Non-printing  characters"  above  for  further
  +       details of the handling of digits following a backslash.
  +
  +       A  back  reference matches whatever actually matched the capturing sub-
  +       pattern in the current subject string, rather  than  anything  matching
          the subpattern itself (see "Subpatterns as subroutines" below for a way
          of doing that). So the pattern


            (sens|respons)e and \1ibility


  -       matches  "sense and sensibility" and "response and responsibility", but
  -       not "sense and responsibility". If caseful matching is in force at  the
  -       time  of the back reference, the case of letters is relevant. For exam-
  +       matches "sense and sensibility" and "response and responsibility",  but
  +       not  "sense and responsibility". If caseful matching is in force at the
  +       time of the back reference, the case of letters is relevant. For  exam-
          ple,


            ((?i)rah)\s+\1


  -       matches "rah rah" and "RAH RAH", but not "RAH  rah",  even  though  the
  +       matches  "rah  rah"  and  "RAH RAH", but not "RAH rah", even though the
          original capturing subpattern is matched caselessly.


  -       Back  references  to named subpatterns use the Python syntax (?P=name).
  +       Back references to named subpatterns use the Python  syntax  (?P=name).
          We could rewrite the above example as follows:


  -         (?<p1>(?i)rah)\s+(?P=p1)
  +         (?P<p1>(?i)rah)\s+(?P=p1)
  +
  +       A  subpattern  that  is  referenced  by  name may appear in the pattern
  +       before or after the reference.


          There may be more than one back reference to the same subpattern. If  a
          subpattern  has  not actually been used in a particular match, any back
  @@ -1109,8 +1191,8 @@
          does  find  an  occurrence  of "bar" that is not preceded by "foo". The
          contents of a lookbehind assertion are restricted  such  that  all  the
          strings it matches must have a fixed length. However, if there are sev-
  -       eral alternatives, they do not all have to have the same fixed  length.
  -       Thus
  +       eral top-level alternatives, they do not all  have  to  have  the  same
  +       fixed length. Thus


            (?<=bullock|donkey)


  @@ -1223,12 +1305,18 @@
          tives in the subpattern, a compile-time error occurs.


          There are three kinds of condition. If the text between the parentheses
  -       consists of a sequence of digits, the condition  is  satisfied  if  the
  -       capturing  subpattern of that number has previously matched. The number
  -       must be greater than zero. Consider the following pattern,  which  con-
  -       tains  non-significant white space to make it more readable (assume the
  -       PCRE_EXTENDED option) and to divide it into three  parts  for  ease  of
  -       discussion:
  +       consists of a sequence of digits, or a sequence of alphanumeric charac-
  +       ters  and underscores, the condition is satisfied if the capturing sub-
  +       pattern of that number or name has previously matched. There is a  pos-
  +       sible  ambiguity here, because subpattern names may consist entirely of
  +       digits. PCRE looks first for a named subpattern; if it cannot find  one
  +       and  the text consists entirely of digits, it looks for a subpattern of
  +       that number, which must be greater than zero.  Using  subpattern  names
  +       that consist entirely of digits is not recommended.
  +
  +       Consider  the  following  pattern, which contains non-significant white
  +       space to make it more readable (assume the PCRE_EXTENDED option) and to
  +       divide it into three parts for ease of discussion:


            ( \( )?    [^()]+    (?(1) \) )


  @@ -1241,12 +1329,16 @@
          tern  is  executed  and  a  closing parenthesis is required. Otherwise,
          since no-pattern is not present, the  subpattern  matches  nothing.  In
          other  words,  this  pattern  matches  a  sequence  of non-parentheses,
  -       optionally enclosed in parentheses.
  +       optionally enclosed in parentheses. Rewriting it to use a named subpat-
  +       tern gives this:


  -       If the condition is the string (R), it is satisfied if a recursive call
  -       to  the pattern or subpattern has been made. At "top level", the condi-
  -       tion is false.  This  is  a  PCRE  extension.  Recursive  patterns  are
  -       described in the next section.
  +         (?P<OPEN> \( )?    [^()]+    (?(OPEN) \) )
  +
  +       If the condition is the string (R), and there is no subpattern with the
  +       name R, the condition is satisfied if a recursive call to  the  pattern
  +       or  subpattern  has  been made. At "top level", the condition is false.
  +       This is a PCRE extension.  Recursive patterns are described in the next
  +       section.


          If  the  condition  is  not  a sequence of digits or (R), it must be an
          assertion.  This may be a positive or negative lookahead or  lookbehind
  @@ -1273,8 +1365,8 @@
          at all.


          If  the PCRE_EXTENDED option is set, an unescaped # character outside a
  -       character class introduces a comment that continues up to the next new-
  -       line character in the pattern.
  +       character class introduces a  comment  that  continues  to  immediately
  +       after the next newline in the pattern.



   RECURSIVE PATTERNS
  @@ -1304,15 +1396,19 @@
          tion.)  The special item (?R) is a recursive call of the entire regular
          expression.


  -       For example, this PCRE pattern solves the  nested  parentheses  problem
  -       (assume  the  PCRE_EXTENDED  option  is  set  so  that  white  space is
  -       ignored):
  +       A recursive subpattern call is always treated as an atomic group.  That
  +       is,  once  it  has  matched some of the subject string, it is never re-
  +       entered, even if it contains untried alternatives and there is a subse-
  +       quent matching failure.
  +
  +       This  PCRE  pattern  solves  the nested parentheses problem (assume the
  +       PCRE_EXTENDED option is set so that white space is ignored):


            \( ( (?>[^()]+) | (?R) )* \)


          First it matches an opening parenthesis. Then it matches any number  of
          substrings  which  can  either  be  a sequence of non-parentheses, or a
  -       recursive match of the pattern itself (that is  a  correctly  parenthe-
  +       recursive match of the pattern itself (that is, a  correctly  parenthe-
          sized substring).  Finally there is a closing parenthesis.


          If  this  were  part of a larger pattern, you would not want to recurse
  @@ -1393,8 +1489,14 @@
            (sens|respons)e and (?1)ibility


          is  used, it does match "sense and responsibility" as well as the other
  -       two strings. Such references must, however, follow  the  subpattern  to
  -       which they refer.
  +       two strings. Such references, if given  numerically,  must  follow  the
  +       subpattern  to which they refer. However, named references can refer to
  +       later subpatterns.
  +
  +       Like recursive subpatterns, a "subroutine" call is always treated as an
  +       atomic  group. That is, once it has matched some of the subject string,
  +       it is never re-entered, even if it contains  untried  alternatives  and
  +       there is a subsequent matching failure.



   CALLOUTS
  @@ -1431,5 +1533,5 @@
          gether. A complete description of the interface to the callout function
          is given in the pcrecallout documentation.


-Last updated: 28 February 2005
-Copyright (c) 1997-2005 University of Cambridge.
+Last updated: 06 June 2006
+Copyright (c) 1997-2006 University of Cambridge.

  Index: pcretest.txt
  ===================================================================
  RCS file: /home/cvs/exim/exim-doc/doc-txt/pcretest.txt,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- pcretest.txt    8 Aug 2005 10:22:14 -0000    1.3
  +++ pcretest.txt    7 Nov 2006 16:50:36 -0000    1.4
  @@ -12,8 +12,7 @@


SYNOPSIS

  -       pcretest [-C] [-d] [-dfa] [-i] [-m] [-o osize] [-p] [-t] [source]
  -            [destination]
  +       pcretest [options] [source] [destination]


          pcretest  was written as a test program for the PCRE regular expression
          library itself, but it can also be used for experimenting with  regular
  @@ -55,6 +54,12 @@
                    per  API  is used to call PCRE. None of the other options has
                    any effect when -p is set.


  +       -q        Do not output the version number of pcretest at the start  of
  +                 execution.
  +
  +       -S size   On  Unix-like  systems,  set the size of the runtime stack to
  +                 size megabytes.
  +
          -t        Run each compile, study, and match many times with  a  timer,
                    and  output resulting time per compile or match (in millisec-
                    onds). Do not set -m with -t, because you will then  get  the
  @@ -76,53 +81,54 @@
          ber of data lines to be matched against the pattern.


          Each  data line is matched separately and independently. If you want to
  -       do multiple-line matches, you have to use the \n escape sequence  in  a
  -       single  line  of  input  to  encode the newline characters. The maximum
  -       length of data line is 30,000 characters.
  -
  -       An empty line signals the end of the data lines, at which point  a  new
  -       regular  expression is read. The regular expressions are given enclosed
  -       in any non-alphanumeric delimiters other than backslash, for example
  +       do multi-line matches, you have to use the \n escape sequence (or \r or
  +       \r\n,  depending  on  the newline setting) in a single line of input to
  +       encode the newline characters. There is no limit on the length of  data
  +       lines; the input buffer is automatically extended if it is too small.
  +
  +       An  empty  line signals the end of the data lines, at which point a new
  +       regular expression is read. The regular expressions are given  enclosed
  +       in any non-alphanumeric delimiters other than backslash, for example:


            /(a|bc)x+yz/


  -       White space before the initial delimiter is ignored. A regular  expres-
  -       sion  may be continued over several input lines, in which case the new-
  -       line characters are included within it. It is possible to  include  the
  +       White  space before the initial delimiter is ignored. A regular expres-
  +       sion may be continued over several input lines, in which case the  new-
  +       line  characters  are included within it. It is possible to include the
          delimiter within the pattern by escaping it, for example


            /abc\/def/


  -       If  you  do  so, the escape and the delimiter form part of the pattern,
  -       but since delimiters are always non-alphanumeric, this does not  affect
  -       its  interpretation.   If the terminating delimiter is immediately fol-
  +       If you do so, the escape and the delimiter form part  of  the  pattern,
  +       but  since delimiters are always non-alphanumeric, this does not affect
  +       its interpretation.  If the terminating delimiter is  immediately  fol-
          lowed by a backslash, for example,


            /abc/\


  -       then a backslash is added to the end of the pattern. This  is  done  to
  -       provide  a  way of testing the error condition that arises if a pattern
  +       then  a  backslash  is added to the end of the pattern. This is done to
  +       provide a way of testing the error condition that arises if  a  pattern
          finishes with a backslash, because


            /abc\/


  -       is interpreted as the first line of a pattern that starts with  "abc/",
  +       is  interpreted as the first line of a pattern that starts with "abc/",
          causing pcretest to read the next line as a continuation of the regular
          expression.



PATTERN MODIFIERS

  -       A pattern may be followed by any number of modifiers, which are  mostly
  -       single  characters.  Following  Perl usage, these are referred to below
  -       as, for example, "the /i modifier", even though the  delimiter  of  the
  -       pattern  need  not always be a slash, and no slash is used when writing
  -       modifiers. Whitespace may appear between the  final  pattern  delimiter
  +       A  pattern may be followed by any number of modifiers, which are mostly
  +       single characters. Following Perl usage, these are  referred  to  below
  +       as,  for  example,  "the /i modifier", even though the delimiter of the
  +       pattern need not always be a slash, and no slash is used  when  writing
  +       modifiers.  Whitespace  may  appear between the final pattern delimiter
          and the first modifier, and between the modifiers themselves.


          The /i, /m, /s, and /x modifiers set the PCRE_CASELESS, PCRE_MULTILINE,
  -       PCRE_DOTALL, or PCRE_EXTENDED  options,  respectively,  when  pcre_com-
  -       pile()  is  called. These four modifier letters have the same effect as
  +       PCRE_DOTALL,  or  PCRE_EXTENDED  options,  respectively, when pcre_com-
  +       pile() is called. These four modifier letters have the same  effect  as
          they do in Perl. For example:


            /caseless/i
  @@ -130,99 +136,111 @@
          The following table shows additional modifiers for setting PCRE options
          that do not correspond to anything in Perl:


  -         /A    PCRE_ANCHORED
  -         /C    PCRE_AUTO_CALLOUT
  -         /E    PCRE_DOLLAR_ENDONLY
  -         /f    PCRE_FIRSTLINE
  -         /N    PCRE_NO_AUTO_CAPTURE
  -         /U    PCRE_UNGREEDY
  -         /X    PCRE_EXTRA
  +         /A       PCRE_ANCHORED
  +         /C       PCRE_AUTO_CALLOUT
  +         /E       PCRE_DOLLAR_ENDONLY
  +         /f       PCRE_FIRSTLINE
  +         /J       PCRE_DUPNAMES
  +         /N       PCRE_NO_AUTO_CAPTURE
  +         /U       PCRE_UNGREEDY
  +         /X       PCRE_EXTRA
  +         /<cr>    PCRE_NEWLINE_CR
  +         /<lf>    PCRE_NEWLINE_LF
  +         /<crlf>  PCRE_NEWLINE_CRLF
  +
  +       Those specifying line endings are literal strings as shown. Details  of
  +       the  meanings of these PCRE options are given in the pcreapi documenta-
  +       tion.
  +
  +   Finding all matches in a string


  -       Searching  for  all  possible matches within each subject string can be
  -       requested by the /g or /G modifier. After  finding  a  match,  PCRE  is
  +       Searching for all possible matches within each subject  string  can  be
  +       requested  by  the  /g  or  /G modifier. After finding a match, PCRE is
          called again to search the remainder of the subject string. The differ-
          ence between /g and /G is that the former uses the startoffset argument
  -       to  pcre_exec()  to  start  searching  at a new point within the entire
  -       string (which is in effect what Perl does), whereas the  latter  passes
  -       over  a  shortened  substring.  This makes a difference to the matching
  +       to pcre_exec() to start searching at a  new  point  within  the  entire
  +       string  (which  is in effect what Perl does), whereas the latter passes
  +       over a shortened substring. This makes a  difference  to  the  matching
          process if the pattern begins with a lookbehind assertion (including \b
          or \B).


  -       If  any  call  to  pcre_exec()  in a /g or /G sequence matches an empty
  -       string, the next call is done with the PCRE_NOTEMPTY and  PCRE_ANCHORED
  -       flags  set in order to search for another, non-empty, match at the same
  -       point.  If this second match fails, the start  offset  is  advanced  by
  -       one,  and  the normal match is retried. This imitates the way Perl han-
  +       If any call to pcre_exec() in a /g or  /G  sequence  matches  an  empty
  +       string,  the next call is done with the PCRE_NOTEMPTY and PCRE_ANCHORED
  +       flags set in order to search for another, non-empty, match at the  same
  +       point.   If  this  second  match fails, the start offset is advanced by
  +       one, and the normal match is retried. This imitates the way  Perl  han-
          dles such cases when using the /g modifier or the split() function.


  +   Other modifiers
  +
          There are yet more modifiers for controlling the way pcretest operates.


  -       The  /+ modifier requests that as well as outputting the substring that
  -       matched the entire pattern, pcretest  should  in  addition  output  the
  -       remainder  of  the  subject  string. This is useful for tests where the
  +       The /+ modifier requests that as well as outputting the substring  that
  +       matched  the  entire  pattern,  pcretest  should in addition output the
  +       remainder of the subject string. This is useful  for  tests  where  the
          subject contains multiple copies of the same substring.


  -       The /L modifier must be followed directly by the name of a locale,  for
  +       The  /L modifier must be followed directly by the name of a locale, for
          example,


            /pattern/Lfr_FR


          For this reason, it must be the last modifier. The given locale is set,
  -       pcre_maketables() is called to build a set of character tables for  the
  -       locale,  and  this  is then passed to pcre_compile() when compiling the
  -       regular expression. Without an /L  modifier,  NULL  is  passed  as  the
  -       tables  pointer; that is, /L applies only to the expression on which it
  +       pcre_maketables()  is called to build a set of character tables for the
  +       locale, and this is then passed to pcre_compile()  when  compiling  the
  +       regular  expression.  Without  an  /L  modifier,  NULL is passed as the
  +       tables pointer; that is, /L applies only to the expression on which  it
          appears.


  -       The /I modifier requests that pcretest  output  information  about  the
  -       compiled  pattern (whether it is anchored, has a fixed first character,
  -       and so on). It does this by calling pcre_fullinfo() after  compiling  a
  -       pattern.  If  the pattern is studied, the results of that are also out-
  +       The  /I  modifier  requests  that pcretest output information about the
  +       compiled pattern (whether it is anchored, has a fixed first  character,
  +       and  so  on). It does this by calling pcre_fullinfo() after compiling a
  +       pattern. If the pattern is studied, the results of that are  also  out-
          put.


          The /D modifier is a PCRE debugging feature, which also assumes /I.  It
  -       causes  the  internal form of compiled regular expressions to be output
  +       causes the internal form of compiled regular expressions to  be  output
          after compilation. If the pattern was studied, the information returned
          is also output.


          The /F modifier causes pcretest to flip the byte order of the fields in
  -       the compiled pattern that  contain  2-byte  and  4-byte  numbers.  This
  -       facility  is  for testing the feature in PCRE that allows it to execute
  +       the  compiled  pattern  that  contain  2-byte  and 4-byte numbers. This
  +       facility is for testing the feature in PCRE that allows it  to  execute
          patterns that were compiled on a host with a different endianness. This
  -       feature  is  not  available  when  the POSIX interface to PCRE is being
  -       used, that is, when the /P pattern modifier is specified. See also  the
  +       feature is not available when the POSIX  interface  to  PCRE  is  being
  +       used,  that is, when the /P pattern modifier is specified. See also the
          section about saving and reloading compiled patterns below.


  -       The  /S  modifier causes pcre_study() to be called after the expression
  +       The /S modifier causes pcre_study() to be called after  the  expression
          has been compiled, and the results used when the expression is matched.


  -       The  /M  modifier causes the size of memory block used to hold the com-
  +       The /M modifier causes the size of memory block used to hold  the  com-
          piled pattern to be output.


  -       The /P modifier causes pcretest to call PCRE via the POSIX wrapper  API
  -       rather  than  its  native  API.  When this is done, all other modifiers
  -       except /i, /m, and /+ are ignored. REG_ICASE is set if /i  is  present,
  -       and  REG_NEWLINE  is  set if /m is present. The wrapper functions force
  -       PCRE_DOLLAR_ENDONLY always, and PCRE_DOTALL unless REG_NEWLINE is  set.
  -
  -       The  /8 modifier causes pcretest to call PCRE with the PCRE_UTF8 option
  -       set. This turns on support for UTF-8 character handling in  PCRE,  pro-
  -       vided  that  it  was  compiled with this support enabled. This modifier
  +       The  /P modifier causes pcretest to call PCRE via the POSIX wrapper API
  +       rather than its native API. When this  is  done,  all  other  modifiers
  +       except  /i,  /m, and /+ are ignored. REG_ICASE is set if /i is present,
  +       and REG_NEWLINE is set if /m is present. The  wrapper  functions  force
  +       PCRE_DOLLAR_ENDONLY  always, and PCRE_DOTALL unless REG_NEWLINE is set.
  +
  +       The /8 modifier causes pcretest to call PCRE with the PCRE_UTF8  option
  +       set.  This  turns on support for UTF-8 character handling in PCRE, pro-
  +       vided that it was compiled with this  support  enabled.  This  modifier
          also causes any non-printing characters in output strings to be printed
          using the \x{hh...} notation if they are valid UTF-8 sequences.


  -       If  the  /?  modifier  is  used  with  /8,  it  causes pcretest to call
  -       pcre_compile() with the  PCRE_NO_UTF8_CHECK  option,  to  suppress  the
  +       If the /? modifier  is  used  with  /8,  it  causes  pcretest  to  call
  +       pcre_compile()  with  the  PCRE_NO_UTF8_CHECK  option,  to suppress the
          checking of the string for UTF-8 validity.



DATA LINES

  -       Before  each  data  line is passed to pcre_exec(), leading and trailing
  -       whitespace is removed, and it is then scanned for \  escapes.  Some  of
  -       these  are  pretty esoteric features, intended for checking out some of
  -       the more complicated features of PCRE. If you are just  testing  "ordi-
  -       nary"  regular  expressions,  you probably don't need any of these. The
  +       Before each data line is passed to pcre_exec(),  leading  and  trailing
  +       whitespace  is  removed,  and it is then scanned for \ escapes. Some of
  +       these are pretty esoteric features, intended for checking out  some  of
  +       the  more  complicated features of PCRE. If you are just testing "ordi-
  +       nary" regular expressions, you probably don't need any  of  these.  The
          following escapes are recognized:


            \a         alarm (= BEL)
  @@ -230,6 +248,8 @@
            \e         escape
            \f         formfeed
            \n         newline
  +         \qdd       set the PCRE_MATCH_LIMIT limit to dd
  +                      (any number of digits)
            \r         carriage return
            \t         tab
            \v         vertical tab
  @@ -238,7 +258,9 @@
            \x{hh...}  hexadecimal character, any number of digits
                         in UTF-8 mode
            \A         pass the PCRE_ANCHORED option to pcre_exec()
  +                      or pcre_dfa_exec()
            \B         pass the PCRE_NOTBOL option to pcre_exec()
  +                      or pcre_dfa_exec()
            \Cdd       call pcre_copy_substring() for substring dd
                         after a successful match (number less than 32)
            \Cname     call pcre_copy_named_substring() for substring
  @@ -262,41 +284,58 @@
                         ated by next non-alphanumeric character)
            \L         call pcre_get_substringlist() after a
                         successful match
  -         \M         discover the minimum MATCH_LIMIT setting
  +         \M         discover the minimum MATCH_LIMIT and
  +                      MATCH_LIMIT_RECURSION settings
            \N         pass the PCRE_NOTEMPTY option to pcre_exec()
  +                      or pcre_dfa_exec()
            \Odd       set the size of the output vector passed to
                         pcre_exec() to dd (any number of digits)
            \P         pass the PCRE_PARTIAL option to pcre_exec()
                         or pcre_dfa_exec()
  +         \Qdd       set the PCRE_MATCH_LIMIT_RECURSION limit to dd
  +                      (any number of digits)
            \R         pass the PCRE_DFA_RESTART option to pcre_dfa_exec()
            \S         output details of memory get/free calls during matching
            \Z         pass the PCRE_NOTEOL option to pcre_exec()
  +                      or pcre_dfa_exec()
            \?         pass the PCRE_NO_UTF8_CHECK option to
  -                      pcre_exec()
  +                      pcre_exec() or pcre_dfa_exec()
            \>dd       start the match at offset dd (any number of digits);
                         this sets the startoffset argument for pcre_exec()
  +                      or pcre_dfa_exec()
  +         \<cr>      pass the PCRE_NEWLINE_CR option to pcre_exec()
  +                      or pcre_dfa_exec()
  +         \<lf>      pass the PCRE_NEWLINE_LF option to pcre_exec()
  +                      or pcre_dfa_exec()
  +         \<crlf>    pass the PCRE_NEWLINE_CRLF option to pcre_exec()
  +                      or pcre_dfa_exec()


  -       A backslash followed by anything else just escapes the  anything  else.
  -       If  the very last character is a backslash, it is ignored. This gives a
  -       way of passing an empty line as data, since a real  empty  line  termi-
  -       nates the data input.
  +       The  escapes  that specify line endings are literal strings, exactly as
  +       shown.  A backslash followed by anything else just escapes the anything
  +       else.  If  the  very last character is a backslash, it is ignored. This
  +       gives a way of passing an empty line as data, since a real  empty  line
  +       terminates the data input.


          If  \M  is present, pcretest calls pcre_exec() several times, with dif-
  -       ferent values in the match_limit field of the  pcre_extra  data  struc-
  -       ture,  until it finds the minimum number that is needed for pcre_exec()
  -       to complete. This number is a measure of the amount  of  recursion  and
  -       backtracking  that takes place, and checking it out can be instructive.
  -       For most simple matches, the number is quite small,  but  for  patterns
  -       with  very large numbers of matching possibilities, it can become large
  -       very quickly with increasing length of subject string.
  +       ferent values in the match_limit and  match_limit_recursion  fields  of
  +       the  pcre_extra  data structure, until it finds the minimum numbers for
  +       each parameter that allow pcre_exec() to complete. The match_limit num-
  +       ber  is  a  measure of the amount of backtracking that takes place, and
  +       checking it out can be instructive. For most simple matches, the number
  +       is  quite  small,  but for patterns with very large numbers of matching
  +       possibilities, it can become large very quickly with increasing  length
  +       of subject string. The match_limit_recursion number is a measure of how
  +       much stack (or, if PCRE is compiled with  NO_RECURSE,  how  much  heap)
  +       memory is needed to complete the match attempt.


  -       When \O is used, the value specified may be higher or  lower  than  the
  +       When  \O  is  used, the value specified may be higher or lower than the
          size set by the -O command line option (or defaulted to 45); \O applies
          only to the call of pcre_exec() for the line in which it appears.


  -       If the /P modifier was present on the pattern, causing the POSIX  wrap-
  -       per  API to be used, only \B and \Z have any effect, causing REG_NOTBOL
  -       and REG_NOTEOL to be passed to regexec() respectively.
  +       If  the /P modifier was present on the pattern, causing the POSIX wrap-
  +       per API to be used, the only option-setting  sequences  that  have  any
  +       effect  are \B and \Z, causing REG_NOTBOL and REG_NOTEOL, respectively,
  +       to be passed to regexec().


          The use of \x{hh...} to represent UTF-8 characters is not dependent  on
          the  use  of  the  /8 modifier on the pattern. It is recognized always.
  @@ -375,14 +414,15 @@


          Note that while patterns can be continued over several lines  (a  plain
          ">" prompt is used for continuations), data lines may not. However new-
  -       lines can be included in data by means of the \n escape.
  +       lines can be included in data by means of the \n escape (or \r or  \r\n
  +       for those newline settings).



OUTPUT FROM THE ALTERNATIVE MATCHING FUNCTION

  -       When the alternative matching function, pcre_dfa_exec(),  is  used  (by
  -       means  of  the \D escape sequence or the -dfa command line option), the
  -       output consists of a list of all the matches that start  at  the  first
  +       When  the  alternative  matching function, pcre_dfa_exec(), is used (by
  +       means of the \D escape sequence or the -dfa command line  option),  the
  +       output  consists  of  a list of all the matches that start at the first
          point in the subject where there is at least one match. For example:


              re> /(tang|tangerine|tan)/
  @@ -391,10 +431,10 @@
             1: tang
             2: tan


  -       (Using  the  normal  matching function on this data finds only "tang".)
  -       The longest matching string is always given first (and numbered  zero).
  +       (Using the normal matching function on this data  finds  only  "tang".)
  +       The  longest matching string is always given first (and numbered zero).


  -       If  /gP  is  present  on  the  pattern,  the search for further matches
  +       If /gP is present on  the  pattern,  the  search  for  further  matches
          resumes at the end of the longest match. For example:


              re> /(tang|tangerine|tan)/g
  @@ -406,16 +446,16 @@
             1: tan
             0: tan


  -       Since the matching function does not  support  substring  capture,  the
  -       escape  sequences  that  are concerned with captured substrings are not
  +       Since  the  matching  function  does not support substring capture, the
  +       escape sequences that are concerned with captured  substrings  are  not
          relevant.



RESTARTING AFTER A PARTIAL MATCH

          When the alternative matching function has given the PCRE_ERROR_PARTIAL
  -       return,  indicating that the subject partially matched the pattern, you
  -       can restart the match with additional subject data by means of  the  \R
  +       return, indicating that the subject partially matched the pattern,  you
  +       can  restart  the match with additional subject data by means of the \R
          escape sequence. For example:


              re> /^?(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)$/
  @@ -424,30 +464,30 @@
            data> n05\R\D
             0: n05


  -       For  further  information  about  partial matching, see the pcrepartial
  +       For further information about partial  matching,  see  the  pcrepartial
          documentation.



CALLOUTS

  -       If the pattern contains any callout requests, pcretest's callout  func-
  -       tion  is  called  during  matching. This works with both matching func-
  +       If  the pattern contains any callout requests, pcretest's callout func-
  +       tion is called during matching. This works  with  both  matching  func-
          tions. By default, the called function displays the callout number, the
  -       start  and  current  positions in the text at the callout time, and the
  +       start and current positions in the text at the callout  time,  and  the
          next pattern item to be tested. For example, the output


            --->pqrabcdef
              0    ^  ^     \d


  -       indicates that callout number 0 occurred for a match  attempt  starting
  -       at  the fourth character of the subject string, when the pointer was at
  -       the seventh character of the data, and when the next pattern  item  was
  -       \d.  Just  one  circumflex is output if the start and current positions
  +       indicates  that  callout number 0 occurred for a match attempt starting
  +       at the fourth character of the subject string, when the pointer was  at
  +       the  seventh  character of the data, and when the next pattern item was
  +       \d. Just one circumflex is output if the start  and  current  positions
          are the same.


          Callouts numbered 255 are assumed to be automatic callouts, inserted as
  -       a  result  of the /C pattern modifier. In this case, instead of showing
  -       the callout number, the offset in the pattern, preceded by a  plus,  is
  +       a result of the /C pattern modifier. In this case, instead  of  showing
  +       the  callout  number, the offset in the pattern, preceded by a plus, is
          output. For example:


              re> /\d?[A-E]\*/C
  @@ -459,68 +499,68 @@
            +10 ^ ^
             0: E*


  -       The  callout  function  in pcretest returns zero (carry on matching) by
  -       default, but you can use a \C item in a data line (as described  above)
  +       The callout function in pcretest returns zero (carry  on  matching)  by
  +       default,  but you can use a \C item in a data line (as described above)
          to change this.


  -       Inserting  callouts can be helpful when using pcretest to check compli-
  -       cated regular expressions. For further information about callouts,  see
  +       Inserting callouts can be helpful when using pcretest to check  compli-
  +       cated  regular expressions. For further information about callouts, see
          the pcrecallout documentation.



SAVING AND RELOADING COMPILED PATTERNS

  -       The  facilities  described  in  this section are not available when the
  +       The facilities described in this section are  not  available  when  the
          POSIX inteface to PCRE is being used, that is, when the /P pattern mod-
          ifier is specified.


          When the POSIX interface is not in use, you can cause pcretest to write
  -       a compiled pattern to a file, by following the modifiers with >  and  a
  +       a  compiled  pattern to a file, by following the modifiers with > and a
          file name.  For example:


            /pattern/im >/some/file


  -       See  the pcreprecompile documentation for a discussion about saving and
  +       See the pcreprecompile documentation for a discussion about saving  and
          re-using compiled patterns.


  -       The data that is written is binary.  The  first  eight  bytes  are  the
  -       length  of  the  compiled  pattern  data  followed by the length of the
  -       optional study data, each written as four  bytes  in  big-endian  order
  -       (most  significant  byte  first). If there is no study data (either the
  +       The  data  that  is  written  is  binary. The first eight bytes are the
  +       length of the compiled pattern data  followed  by  the  length  of  the
  +       optional  study  data,  each  written as four bytes in big-endian order
  +       (most significant byte first). If there is no study  data  (either  the
          pattern was not studied, or studying did not return any data), the sec-
  -       ond  length  is  zero. The lengths are followed by an exact copy of the
  +       ond length is zero. The lengths are followed by an exact  copy  of  the
          compiled pattern. If there is additional study data, this follows imme-
  -       diately  after  the  compiled pattern. After writing the file, pcretest
  +       diately after the compiled pattern. After writing  the  file,  pcretest
          expects to read a new pattern.


          A saved pattern can be reloaded into pcretest by specifing < and a file
  -       name  instead  of  a pattern. The name of the file must not contain a <
  -       character, as otherwise pcretest will interpret the line as  a  pattern
  +       name instead of a pattern. The name of the file must not  contain  a  <
  +       character,  as  otherwise pcretest will interpret the line as a pattern
          delimited by < characters.  For example:


             re> </some/file
            Compiled regex loaded from /some/file
            No study data


  -       When  the pattern has been loaded, pcretest proceeds to read data lines
  +       When the pattern has been loaded, pcretest proceeds to read data  lines
          in the usual way.


  -       You can copy a file written by pcretest to a different host and  reload
  -       it  there,  even  if the new host has opposite endianness to the one on
  -       which the pattern was compiled. For example, you can compile on an  i86
  +       You  can copy a file written by pcretest to a different host and reload
  +       it there, even if the new host has opposite endianness to  the  one  on
  +       which  the pattern was compiled. For example, you can compile on an i86
          machine and run on a SPARC machine.


  -       File  names  for  saving and reloading can be absolute or relative, but
  -       note that the shell facility of expanding a file name that starts  with
  +       File names for saving and reloading can be absolute  or  relative,  but
  +       note  that the shell facility of expanding a file name that starts with
          a tilde (~) is not available.


  -       The  ability to save and reload files in pcretest is intended for test-
  -       ing and experimentation. It is not intended for production use  because
  -       only  a  single pattern can be written to a file. Furthermore, there is
  -       no facility for supplying  custom  character  tables  for  use  with  a
  -       reloaded  pattern.  If  the  original  pattern was compiled with custom
  -       tables, an attempt to match a subject string using a  reloaded  pattern
  -       is  likely to cause pcretest to crash.  Finally, if you attempt to load
  +       The ability to save and reload files in pcretest is intended for  test-
  +       ing  and experimentation. It is not intended for production use because
  +       only a single pattern can be written to a file. Furthermore,  there  is
  +       no  facility  for  supplying  custom  character  tables  for use with a
  +       reloaded pattern. If the original  pattern  was  compiled  with  custom
  +       tables,  an  attempt to match a subject string using a reloaded pattern
  +       is likely to cause pcretest to crash.  Finally, if you attempt to  load
          a file that is not in the correct format, the result is undefined.



  @@ -530,5 +570,5 @@
          University Computing Service,
          Cambridge CB2 3QG, England.


-Last updated: 28 February 2005
-Copyright (c) 1997-2005 University of Cambridge.
+Last updated: 29 June 2006
+Copyright (c) 1997-2006 University of Cambridge.

  Index: MakeLinks
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/scripts/MakeLinks,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- MakeLinks    16 Oct 2006 15:44:36 -0000    1.8
  +++ MakeLinks    7 Nov 2006 16:50:36 -0000    1.9
  @@ -1,5 +1,5 @@
   #!/bin/sh
  -# $Cambridge: exim/exim-src/scripts/MakeLinks,v 1.8 2006/10/16 15:44:36 ph10 Exp $
  +# $Cambridge: exim/exim-src/scripts/MakeLinks,v 1.9 2006/11/07 16:50:36 ph10 Exp $


   # Script to build links for all the exim source files from the system-
   # specific build directory. It should be run from within that directory.
  @@ -43,7 +43,7 @@
   ln -s ../../src/pcre/pcre_exec.c         pcre_exec.c
   ln -s ../../src/pcre/pcre_fullinfo.c     pcre_fullinfo.c
   ln -s ../../src/pcre/pcretest.c          pcretest.c
  -ln -s ../../src/pcre/pcre_printint.c     pcre_printint.c
  +ln -s ../../src/pcre/pcre_printint.src   pcre_printint.src
   ln -s ../../src/pcre/pcre_study.c        pcre_study.c
   ln -s ../../src/pcre/pcre_tables.c       pcre_tables.c
   ln -s ../../src/pcre/pcre_try_flipped.c  pcre_try_flipped.c


Index: pcre_printint.src
====================================================================
/* $Cambridge: exim/exim-src/src/pcre/pcre_printint.src,v 1.1 2006/11/07 16:50:36 ph10 Exp $ */

  /*************************************************
  *      Perl-Compatible Regular Expressions       *
  *************************************************/


/* PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.

                         Written by Philip Hazel
             Copyright (c) 1997-2005 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

      * Redistributions of source code must retain the above copyright notice,
        this list of conditions and the following disclaimer.


      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.


      * Neither the name of the University of Cambridge nor the names of its
        contributors may be used to endorse or promote products derived from
        this software without specific prior written permission.


THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/


/* This module contains a PCRE private debugging function for printing out the
internal form of a compiled regular expression, along with some supporting
local functions. This source file is used in two places:

(1) It is #included by pcre_compile.c when it is compiled in debugging mode
(DEBUG defined in pcre_internal.h). It is not included in production compiles.

(2) It is always #included by pcretest.c, which can be asked to print out a
compiled regex for debugging purposes. */


static const char *OP_names[] = { OP_NAME_LIST };


  /*************************************************
  *       Print single- or multi-byte character    *
  *************************************************/


static int
print_char(FILE *f, uschar *ptr, BOOL utf8)
{
int c = *ptr;

  if (!utf8 || (c & 0xc0) != 0xc0)
    {
    if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c);
    return 0;
    }
  else
    {
    int i;
    int a = _pcre_utf8_table4[c & 0x3f];  /* Number of additional bytes */
    int s = 6*a;
    c = (c & _pcre_utf8_table3[a]) << s;
    for (i = 1; i <= a; i++)
      {
      /* This is a check for malformed UTF-8; it should only occur if the sanity
      check has been turned off. Rather than swallow random bytes, just stop if
      we hit a bad one. Print it with \X instead of \x as an indication. */


      if ((ptr[i] & 0xc0) != 0x80)
        {
        fprintf(f, "\\X{%x}", c);
        return i - 1;
        }


      /* The byte is OK */


      s -= 6;
      c |= (ptr[i] & 0x3f) << s;
      }
    if (c < 128) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c);
    return a;
    }
  }




  /*************************************************
  *          Find Unicode property name            *
  *************************************************/


  static const char *
  get_ucpname(int ptype, int pvalue)
  {
  #ifdef SUPPORT_UCP
  int i;
  for (i = _pcre_utt_size; i >= 0; i--)
    {
    if (ptype == _pcre_utt[i].type && pvalue == _pcre_utt[i].value) break;
    }
  return (i >= 0)? _pcre_utt[i].name : "??";
  #else
  /* It gets harder and harder to shut off unwanted compiler warnings. */
  ptype = ptype * pvalue;
  return (ptype == pvalue)? "??" : "??";
  #endif
  }




  /*************************************************
  *         Print compiled regex                   *
  *************************************************/


/* Make this function work for a regex with integers either byte order.
However, we assume that what we are passed is a compiled regex. */

static void
pcre_printint(pcre *external_re, FILE *f)
{
real_pcre *re = (real_pcre *)external_re;
uschar *codestart, *code;
BOOL utf8;

unsigned int options = re->options;
int offset = re->name_table_offset;
int count = re->name_count;
int size = re->name_entry_size;

  if (re->magic_number != MAGIC_NUMBER)
    {
    offset = ((offset << 8) & 0xff00) | ((offset >> 8) & 0xff);
    count = ((count << 8) & 0xff00) | ((count >> 8) & 0xff);
    size = ((size << 8) & 0xff00) | ((size >> 8) & 0xff);
    options = ((options << 24) & 0xff000000) |
              ((options <<  8) & 0x00ff0000) |
              ((options >>  8) & 0x0000ff00) |
              ((options >> 24) & 0x000000ff);
    }


code = codestart = (uschar *)re + offset + count * size;
utf8 = (options & PCRE_UTF8) != 0;

  for(;;)
    {
    uschar *ccode;
    int c;
    int extra = 0;


    fprintf(f, "%3d ", (int)(code - codestart));


    if (*code >= OP_BRA)
      {
      if (*code - OP_BRA > EXTRACT_BASIC_MAX)
        fprintf(f, "%3d Bra extra\n", GET(code, 1));
      else
        fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA);
      code += _pcre_OP_lengths[OP_BRA];
      continue;
      }


    switch(*code)
      {
      case OP_END:
      fprintf(f, "    %s\n", OP_names[*code]);
      fprintf(f, "------------------------------------------------------------------\n");
      return;


      case OP_OPT:
      fprintf(f, " %.2x %s", code[1], OP_names[*code]);
      break;


      case OP_CHAR:
      fprintf(f, "    ");
      do
        {
        code++;
        code += 1 + print_char(f, code, utf8);
        }
      while (*code == OP_CHAR);
      fprintf(f, "\n");
      continue;


      case OP_CHARNC:
      fprintf(f, " NC ");
      do
        {
        code++;
        code += 1 + print_char(f, code, utf8);
        }
      while (*code == OP_CHARNC);
      fprintf(f, "\n");
      continue;


      case OP_KETRMAX:
      case OP_KETRMIN:
      case OP_ALT:
      case OP_KET:
      case OP_ASSERT:
      case OP_ASSERT_NOT:
      case OP_ASSERTBACK:
      case OP_ASSERTBACK_NOT:
      case OP_ONCE:
      case OP_COND:
      case OP_REVERSE:
      fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
      break;


      case OP_BRANUMBER:
      printf("%3d %s", GET2(code, 1), OP_names[*code]);
      break;


      case OP_CREF:
      if (GET2(code, 1) == CREF_RECURSE)
        fprintf(f, "    Cond recurse");
      else
        fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
      break;


      case OP_STAR:
      case OP_MINSTAR:
      case OP_PLUS:
      case OP_MINPLUS:
      case OP_QUERY:
      case OP_MINQUERY:
      case OP_TYPESTAR:
      case OP_TYPEMINSTAR:
      case OP_TYPEPLUS:
      case OP_TYPEMINPLUS:
      case OP_TYPEQUERY:
      case OP_TYPEMINQUERY:
      fprintf(f, "    ");
      if (*code >= OP_TYPESTAR)
        {
        fprintf(f, "%s", OP_names[code[1]]);
        if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
          {
          fprintf(f, " %s ", get_ucpname(code[2], code[3]));
          extra = 2;
          }
        }
      else extra = print_char(f, code+1, utf8);
      fprintf(f, "%s", OP_names[*code]);
      break;


      case OP_EXACT:
      case OP_UPTO:
      case OP_MINUPTO:
      fprintf(f, "    ");
      extra = print_char(f, code+3, utf8);
      fprintf(f, "{");
      if (*code != OP_EXACT) fprintf(f, ",");
      fprintf(f, "%d}", GET2(code,1));
      if (*code == OP_MINUPTO) fprintf(f, "?");
      break;


      case OP_TYPEEXACT:
      case OP_TYPEUPTO:
      case OP_TYPEMINUPTO:
      fprintf(f, "    %s", OP_names[code[3]]);
      if (code[3] == OP_PROP || code[3] == OP_NOTPROP)
        {
        fprintf(f, " %s ", get_ucpname(code[4], code[5]));
        extra = 2;
        }
      fprintf(f, "{");
      if (*code != OP_TYPEEXACT) fprintf(f, "0,");
      fprintf(f, "%d}", GET2(code,1));
      if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
      break;


      case OP_NOT:
      if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
        else fprintf(f, "    [^\\x%02x]", c);
      break;


      case OP_NOTSTAR:
      case OP_NOTMINSTAR:
      case OP_NOTPLUS:
      case OP_NOTMINPLUS:
      case OP_NOTQUERY:
      case OP_NOTMINQUERY:
      if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
        else fprintf(f, "    [^\\x%02x]", c);
      fprintf(f, "%s", OP_names[*code]);
      break;


      case OP_NOTEXACT:
      case OP_NOTUPTO:
      case OP_NOTMINUPTO:
      if (isprint(c = code[3])) fprintf(f, "    [^%c]{", c);
        else fprintf(f, "    [^\\x%02x]{", c);
      if (*code != OP_NOTEXACT) fprintf(f, "0,");
      fprintf(f, "%d}", GET2(code,1));
      if (*code == OP_NOTMINUPTO) fprintf(f, "?");
      break;


      case OP_RECURSE:
      fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
      break;


      case OP_REF:
      fprintf(f, "    \\%d", GET2(code,1));
      ccode = code + _pcre_OP_lengths[*code];
      goto CLASS_REF_REPEAT;


      case OP_CALLOUT:
      fprintf(f, "    %s %d %d %d", OP_names[*code], code[1], GET(code,2),
        GET(code, 2 + LINK_SIZE));
      break;


      case OP_PROP:
      case OP_NOTPROP:
      fprintf(f, "    %s %s", OP_names[*code], get_ucpname(code[1], code[2]));
      break;


      /* OP_XCLASS can only occur in UTF-8 mode. However, there's no harm in
      having this code always here, and it makes it less messy without all those
      #ifdefs. */


      case OP_CLASS:
      case OP_NCLASS:
      case OP_XCLASS:
        {
        int i, min, max;
        BOOL printmap;


        fprintf(f, "    [");


        if (*code == OP_XCLASS)
          {
          extra = GET(code, 1);
          ccode = code + LINK_SIZE + 1;
          printmap = (*ccode & XCL_MAP) != 0;
          if ((*ccode++ & XCL_NOT) != 0) fprintf(f, "^");
          }
        else
          {
          printmap = TRUE;
          ccode = code + 1;
          }


        /* Print a bit map */


        if (printmap)
          {
          for (i = 0; i < 256; i++)
            {
            if ((ccode[i/8] & (1 << (i&7))) != 0)
              {
              int j;
              for (j = i+1; j < 256; j++)
                if ((ccode[j/8] & (1 << (j&7))) == 0) break;
              if (i == '-' || i == ']') fprintf(f, "\\");
              if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i);
              if (--j > i)
                {
                if (j != i + 1) fprintf(f, "-");
                if (j == '-' || j == ']') fprintf(f, "\\");
                if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j);
                }
              i = j;
              }
            }
          ccode += 32;
          }


        /* For an XCLASS there is always some additional data */


        if (*code == OP_XCLASS)
          {
          int ch;
          while ((ch = *ccode++) != XCL_END)
            {
            if (ch == XCL_PROP)
              {
              int ptype = *ccode++;
              int pvalue = *ccode++;
              fprintf(f, "\\p{%s}", get_ucpname(ptype, pvalue));
              }
            else if (ch == XCL_NOTPROP)
              {
              int ptype = *ccode++;
              int pvalue = *ccode++;
              fprintf(f, "\\P{%s}", get_ucpname(ptype, pvalue));
              }
            else
              {
              ccode += 1 + print_char(f, ccode, TRUE);
              if (ch == XCL_RANGE)
                {
                fprintf(f, "-");
                ccode += 1 + print_char(f, ccode, TRUE);
                }
              }
            }
          }


        /* Indicate a non-UTF8 class which was created by negation */


        fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");


        /* Handle repeats after a class or a back reference */


        CLASS_REF_REPEAT:
        switch(*ccode)
          {
          case OP_CRSTAR:
          case OP_CRMINSTAR:
          case OP_CRPLUS:
          case OP_CRMINPLUS:
          case OP_CRQUERY:
          case OP_CRMINQUERY:
          fprintf(f, "%s", OP_names[*ccode]);
          extra += _pcre_OP_lengths[*ccode];
          break;


          case OP_CRRANGE:
          case OP_CRMINRANGE:
          min = GET2(ccode,1);
          max = GET2(ccode,3);
          if (max == 0) fprintf(f, "{%d,}", min);
          else fprintf(f, "{%d,%d}", min, max);
          if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
          extra += _pcre_OP_lengths[*ccode];
          break;


          /* Do nothing if it's not a repeat; this code stops picky compilers
          warning about the lack of a default code path. */


          default:
          break;
          }
        }
      break;


      /* Anything else is just an item with no data*/


      default:
      fprintf(f, "    %s", OP_names[*code]);
      break;
      }


    code += _pcre_OP_lengths[*code] + extra;
    fprintf(f, "\n");
    }
  }


/* End of pcre_printint.src */

  Index: ChangeLog
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/ChangeLog,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ChangeLog    8 Aug 2005 10:22:14 -0000    1.3
  +++ ChangeLog    7 Nov 2006 16:50:36 -0000    1.4
  @@ -1,6 +1,459 @@
   ChangeLog for PCRE
   ------------------


  +Version 6.7 04-Jul-06
  +---------------------
  +
  + 1. In order to handle tests when input lines are enormously long, pcretest has
  +    been re-factored so that it automatically extends its buffers when
  +    necessary. The code is crude, but this _is_ just a test program. The
  +    default size has been increased from 32K to 50K.
  +
  + 2. The code in pcre_study() was using the value of the re argument before
  +    testing it for NULL. (Of course, in any sensible call of the function, it
  +    won't be NULL.)
  +
  + 3. The memmove() emulation function in pcre_internal.h, which is used on
  +    systems that lack both memmove() and bcopy() - that is, hardly ever -
  +    was missing a "static" storage class specifier.
  +
  + 4. When UTF-8 mode was not set, PCRE looped when compiling certain patterns
  +    containing an extended class (one that cannot be represented by a bitmap
  +    because it contains high-valued characters or Unicode property items, e.g.
  +    [\pZ]). Almost always one would set UTF-8 mode when processing such a
  +    pattern, but PCRE should not loop if you do not (it no longer does).
  +    [Detail: two cases were found: (a) a repeated subpattern containing an
  +    extended class; (b) a recursive reference to a subpattern that followed a
  +    previous extended class. It wasn't skipping over the extended class
  +    correctly when UTF-8 mode was not set.]
  +
  + 5. A negated single-character class was not being recognized as fixed-length
  +    in lookbehind assertions such as (?<=[^f]), leading to an incorrect
  +    compile error "lookbehind assertion is not fixed length".
  +
  + 6. The RunPerlTest auxiliary script was showing an unexpected difference
  +    between PCRE and Perl for UTF-8 tests. It turns out that it is hard to
  +    write a Perl script that can interpret lines of an input file either as
  +    byte characters or as UTF-8, which is what "perltest" was being required to
  +    do for the non-UTF-8 and UTF-8 tests, respectively. Essentially what you
  +    can't do is switch easily at run time between having the "use utf8;" pragma
  +    or not. In the end, I fudged it by using the RunPerlTest script to insert
  +    "use utf8;" explicitly for the UTF-8 tests.
  +
  + 7. In multiline (/m) mode, PCRE was matching ^ after a terminating newline at
  +    the end of the subject string, contrary to the documentation and to what
  +    Perl does. This was true of both matching functions. Now it matches only at
  +    the start of the subject and immediately after *internal* newlines.
  +
  + 8. A call of pcre_fullinfo() from pcretest to get the option bits was passing
  +    a pointer to an int instead of a pointer to an unsigned long int. This
  +    caused problems on 64-bit systems.
  +
  + 9. Applied a patch from the folks at Google to pcrecpp.cc, to fix "another
  +    instance of the 'standard' template library not being so standard".
  +
  +10. There was no check on the number of named subpatterns nor the maximum
  +    length of a subpattern name. The product of these values is used to compute
  +    the size of the memory block for a compiled pattern. By supplying a very
  +    long subpattern name and a large number of named subpatterns, the size
  +    computation could be caused to overflow. This is now prevented by limiting
  +    the length of names to 32 characters, and the number of named subpatterns
  +    to 10,000.
  +
  +11. Subpatterns that are repeated with specific counts have to be replicated in
  +    the compiled pattern. The size of memory for this was computed from the
  +    length of the subpattern and the repeat count. The latter is limited to
  +    65535, but there was no limit on the former, meaning that integer overflow
  +    could in principle occur. The compiled length of a repeated subpattern is
  +    now limited to 30,000 bytes in order to prevent this.
  +
  +12. Added the optional facility to have named substrings with the same name.
  +
  +13. Added the ability to use a named substring as a condition, using the
  +    Python syntax: (?(name)yes|no). This overloads (?(R)... and names that
  +    are numbers (not recommended). Forward references are permitted.
  +
  +14. Added forward references in named backreferences (if you see what I mean).
  +
  +15. In UTF-8 mode, with the PCRE_DOTALL option set, a quantified dot in the
  +    pattern could run off the end of the subject. For example, the pattern
  +    "(?s)(.{1,5})"8 did this with the subject "ab".
  +
  +16. If PCRE_DOTALL or PCRE_MULTILINE were set, pcre_dfa_exec() behaved as if
  +    PCRE_CASELESS was set when matching characters that were quantified with ?
  +    or *.
  +
  +17. A character class other than a single negated character that had a minimum
  +    but no maximum quantifier - for example [ab]{6,} - was not handled
  +    correctly by pce_dfa_exec(). It would match only one character.
  +
  +18. A valid (though odd) pattern that looked like a POSIX character
  +    class but used an invalid character after [ (for example [[,abc,]]) caused
  +    pcre_compile() to give the error "Failed: internal error: code overflow" or
  +    in some cases to crash with a glibc free() error. This could even happen if
  +    the pattern terminated after [[ but there just happened to be a sequence of
  +    letters, a binary zero, and a closing ] in the memory that followed.
  +
  +19. Perl's treatment of octal escapes in the range \400 to \777 has changed
  +    over the years. Originally (before any Unicode support), just the bottom 8
  +    bits were taken. Thus, for example, \500 really meant \100. Nowadays the
  +    output from "man perlunicode" includes this:
  +
  +      The regular expression compiler produces polymorphic opcodes.  That
  +      is, the pattern adapts to the data and automatically switches to
  +      the Unicode character scheme when presented with Unicode data--or
  +      instead uses a traditional byte scheme when presented with byte
  +      data.
  +
  +    Sadly, a wide octal escape does not cause a switch, and in a string with
  +    no other multibyte characters, these octal escapes are treated as before.
  +    Thus, in Perl, the pattern  /\500/ actually matches \100 but the pattern
  +    /\500|\x{1ff}/ matches \500 or \777 because the whole thing is treated as a
  +    Unicode string.
  +
  +    I have not perpetrated such confusion in PCRE. Up till now, it took just
  +    the bottom 8 bits, as in old Perl. I have now made octal escapes with
  +    values greater than \377 illegal in non-UTF-8 mode. In UTF-8 mode they
  +    translate to the appropriate multibyte character.
  +
  +29. Applied some refactoring to reduce the number of warnings from Microsoft
  +    and Borland compilers. This has included removing the fudge introduced
  +    seven years ago for the OS/2 compiler (see 2.02/2 below) because it caused
  +    a warning about an unused variable.
  +
  +21. PCRE has not included VT (character 0x0b) in the set of whitespace
  +    characters since release 4.0, because Perl (from release 5.004) does not.
  +    [Or at least, is documented not to: some releases seem to be in conflict
  +    with the documentation.] However, when a pattern was studied with
  +    pcre_study() and all its branches started with \s, PCRE still included VT
  +    as a possible starting character. Of course, this did no harm; it just
  +    caused an unnecessary match attempt.
  +
  +22. Removed a now-redundant internal flag bit that recorded the fact that case
  +    dependency changed within the pattern. This was once needed for "required
  +    byte" processing, but is no longer used. This recovers a now-scarce options
  +    bit. Also moved the least significant internal flag bit to the most-
  +    significant bit of the word, which was not previously used (hangover from
  +    the days when it was an int rather than a uint) to free up another bit for
  +    the future.
  +
  +23. Added support for CRLF line endings as well as CR and LF. As well as the
  +    default being selectable at build time, it can now be changed at runtime
  +    via the PCRE_NEWLINE_xxx flags. There are now options for pcregrep to
  +    specify that it is scanning data with non-default line endings.
  +
  +24. Changed the definition of CXXLINK to make it agree with the definition of
  +    LINK in the Makefile, by replacing LDFLAGS to CXXFLAGS.
  +
  +25. Applied Ian Taylor's patches to avoid using another stack frame for tail
  +    recursions. This makes a big different to stack usage for some patterns.
  +
  +26. If a subpattern containing a named recursion or subroutine reference such
  +    as (?P>B) was quantified, for example (xxx(?P>B)){3}, the calculation of
  +    the space required for the compiled pattern went wrong and gave too small a
  +    value. Depending on the environment, this could lead to "Failed: internal
  +    error: code overflow at offset 49" or "glibc detected double free or
  +    corruption" errors.
  +
  +27. Applied patches from Google (a) to support the new newline modes and (b) to
  +    advance over multibyte UTF-8 characters in GlobalReplace.
  +
  +28. Change free() to pcre_free() in pcredemo.c. Apparently this makes a
  +    difference for some implementation of PCRE in some Windows version.
  +
  +29. Added some extra testing facilities to pcretest:
  +
  +    \q<number>   in a data line sets the "match limit" value
  +    \Q<number>   in a data line sets the "match recursion limt" value
  +    -S <number>  sets the stack size, where <number> is in megabytes
  +
  +    The -S option isn't available for Windows.
  +
  +
  +Version 6.6 06-Feb-06
  +---------------------
  +
  + 1. Change 16(a) for 6.5 broke things, because PCRE_DATA_SCOPE was not defined
  +    in pcreposix.h. I have copied the definition from pcre.h.
  +
  + 2. Change 25 for 6.5 broke compilation in a build directory out-of-tree
  +    because pcre.h is no longer a built file.
  +
  + 3. Added Jeff Friedl's additional debugging patches to pcregrep. These are
  +    not normally included in the compiled code.
  +
  +
  +Version 6.5 01-Feb-06
  +---------------------
  +
  + 1. When using the partial match feature with pcre_dfa_exec(), it was not
  +    anchoring the second and subsequent partial matches at the new starting
  +    point. This could lead to incorrect results. For example, with the pattern
  +    /1234/, partially matching against "123" and then "a4" gave a match.
  +
  + 2. Changes to pcregrep:
  +
  +    (a) All non-match returns from pcre_exec() were being treated as failures
  +        to match the line. Now, unless the error is PCRE_ERROR_NOMATCH, an
  +        error message is output. Some extra information is given for the
  +        PCRE_ERROR_MATCHLIMIT and PCRE_ERROR_RECURSIONLIMIT errors, which are
  +        probably the only errors that are likely to be caused by users (by
  +        specifying a regex that has nested indefinite repeats, for instance).
  +        If there are more than 20 of these errors, pcregrep is abandoned.
  +
  +    (b) A binary zero was treated as data while matching, but terminated the
  +        output line if it was written out. This has been fixed: binary zeroes
  +        are now no different to any other data bytes.
  +
  +    (c) Whichever of the LC_ALL or LC_CTYPE environment variables is set is
  +        used to set a locale for matching. The --locale=xxxx long option has
  +        been added (no short equivalent) to specify a locale explicitly on the
  +        pcregrep command, overriding the environment variables.
  +
  +    (d) When -B was used with -n, some line numbers in the output were one less
  +        than they should have been.
  +
  +    (e) Added the -o (--only-matching) option.
  +
  +    (f) If -A or -C was used with -c (count only), some lines of context were
  +        accidentally printed for the final match.
  +
  +    (g) Added the -H (--with-filename) option.
  +
  +    (h) The combination of options -rh failed to suppress file names for files
  +        that were found from directory arguments.
  +
  +    (i) Added the -D (--devices) and -d (--directories) options.
  +
  +    (j) Added the -F (--fixed-strings) option.
  +
  +    (k) Allow "-" to be used as a file name for -f as well as for a data file.
  +
  +    (l) Added the --colo(u)r option.
  +
  +    (m) Added Jeffrey Friedl's -S testing option, but within #ifdefs so that it
  +        is not present by default.
  +
  + 3. A nasty bug was discovered in the handling of recursive patterns, that is,
  +    items such as (?R) or (?1), when the recursion could match a number of
  +    alternatives. If it matched one of the alternatives, but subsequently,
  +    outside the recursion, there was a failure, the code tried to back up into
  +    the recursion. However, because of the way PCRE is implemented, this is not
  +    possible, and the result was an incorrect result from the match.
  +
  +    In order to prevent this happening, the specification of recursion has
  +    been changed so that all such subpatterns are automatically treated as
  +    atomic groups. Thus, for example, (?R) is treated as if it were (?>(?R)).
  +
  + 4. I had overlooked the fact that, in some locales, there are characters for
  +    which isalpha() is true but neither isupper() nor islower() are true. In
  +    the fr_FR locale, for instance, the \xAA and \xBA characters (ordmasculine
  +    and ordfeminine) are like this. This affected the treatment of \w and \W
  +    when they appeared in character classes, but not when they appeared outside
  +    a character class. The bit map for "word" characters is now created
  +    separately from the results of isalnum() instead of just taking it from the
  +    upper, lower, and digit maps. (Plus the underscore character, of course.)
  +
  + 5. The above bug also affected the handling of POSIX character classes such as
  +    [[:alpha:]] and [[:alnum:]]. These do not have their own bit maps in PCRE's
  +    permanent tables. Instead, the bit maps for such a class were previously
  +    created as the appropriate unions of the upper, lower, and digit bitmaps.
  +    Now they are created by subtraction from the [[:word:]] class, which has
  +    its own bitmap.
  +
  + 6. The [[:blank:]] character class matches horizontal, but not vertical space.
  +    It is created by subtracting the vertical space characters (\x09, \x0a,
  +    \x0b, \x0c) from the [[:space:]] bitmap. Previously, however, the
  +    subtraction was done in the overall bitmap for a character class, meaning
  +    that a class such as [\x0c[:blank:]] was incorrect because \x0c would not
  +    be recognized. This bug has been fixed.
  +
  + 7. Patches from the folks at Google:
  +
  +      (a) pcrecpp.cc: "to handle a corner case that may or may not happen in
  +      real life, but is still worth protecting against".
  +
  +      (b) pcrecpp.cc: "corrects a bug when negative radixes are used with
  +      regular expressions".
  +
  +      (c) pcre_scanner.cc: avoid use of std::count() because not all systems
  +      have it.
  +
  +      (d) Split off pcrecpparg.h from pcrecpp.h and had the former built by
  +      "configure" and the latter not, in order to fix a problem somebody had
  +      with compiling the Arg class on HP-UX.
  +
  +      (e) Improve the error-handling of the C++ wrapper a little bit.
  +
  +      (f) New tests for checking recursion limiting.
  +
  + 8. The pcre_memmove() function, which is used only if the environment does not
  +    have a standard memmove() function (and is therefore rarely compiled),
  +    contained two bugs: (a) use of int instead of size_t, and (b) it was not
  +    returning a result (though PCRE never actually uses the result).
  +
  + 9. In the POSIX regexec() interface, if nmatch is specified as a ridiculously
  +    large number - greater than INT_MAX/(3*sizeof(int)) - REG_ESPACE is
  +    returned instead of calling malloc() with an overflowing number that would
  +    most likely cause subsequent chaos.
  +
  +10. The debugging option of pcretest was not showing the NO_AUTO_CAPTURE flag.
  +
  +11. The POSIX flag REG_NOSUB is now supported. When a pattern that was compiled
  +    with this option is matched, the nmatch and pmatch options of regexec() are
  +    ignored.
  +
  +12. Added REG_UTF8 to the POSIX interface. This is not defined by POSIX, but is
  +    provided in case anyone wants to the the POSIX interface with UTF-8
  +    strings.
  +
  +13. Added CXXLDFLAGS to the Makefile parameters to provide settings only on the
  +    C++ linking (needed for some HP-UX environments).
  +
  +14. Avoid compiler warnings in get_ucpname() when compiled without UCP support
  +    (unused parameter) and in the pcre_printint() function (omitted "default"
  +    switch label when the default is to do nothing).
  +
  +15. Added some code to make it possible, when PCRE is compiled as a C++
  +    library, to replace subject pointers for pcre_exec() with a smart pointer
  +    class, thus making it possible to process discontinuous strings.
  +
  +16. The two macros PCRE_EXPORT and PCRE_DATA_SCOPE are confusing, and perform
  +    much the same function. They were added by different people who were trying
  +    to make PCRE easy to compile on non-Unix systems. It has been suggested
  +    that PCRE_EXPORT be abolished now that there is more automatic apparatus
  +    for compiling on Windows systems. I have therefore replaced it with
  +    PCRE_DATA_SCOPE. This is set automatically for Windows; if not set it
  +    defaults to "extern" for C or "extern C" for C++, which works fine on
  +    Unix-like systems. It is now possible to override the value of PCRE_DATA_
  +    SCOPE with something explicit in config.h. In addition:
  +
  +    (a) pcreposix.h still had just "extern" instead of either of these macros;
  +        I have replaced it with PCRE_DATA_SCOPE.
  +
  +    (b) Functions such as _pcre_xclass(), which are internal to the library,
  +        but external in the C sense, all had PCRE_EXPORT in their definitions.
  +        This is apparently wrong for the Windows case, so I have removed it.
  +        (It makes no difference on Unix-like systems.)
  +
  +17. Added a new limit, MATCH_LIMIT_RECURSION, which limits the depth of nesting
  +    of recursive calls to match(). This is different to MATCH_LIMIT because
  +    that limits the total number of calls to match(), not all of which increase
  +    the depth of recursion. Limiting the recursion depth limits the amount of
  +    stack (or heap if NO_RECURSE is set) that is used. The default can be set
  +    when PCRE is compiled, and changed at run time. A patch from Google adds
  +    this functionality to the C++ interface.
  +
  +18. Changes to the handling of Unicode character properties:
  +
  +    (a) Updated the table to Unicode 4.1.0.
  +
  +    (b) Recognize characters that are not in the table as "Cn" (undefined).
  +
  +    (c) I revised the way the table is implemented to a much improved format
  +        which includes recognition of ranges. It now supports the ranges that
  +        are defined in UnicodeData.txt, and it also amalgamates other
  +        characters into ranges. This has reduced the number of entries in the
  +        table from around 16,000 to around 3,000, thus reducing its size
  +        considerably. I realized I did not need to use a tree structure after
  +        all - a binary chop search is just as efficient. Having reduced the
  +        number of entries, I extended their size from 6 bytes to 8 bytes to
  +        allow for more data.
  +
  +    (d) Added support for Unicode script names via properties such as \p{Han}.
  +
  +19. In UTF-8 mode, a backslash followed by a non-Ascii character was not
  +    matching that character.
  +
  +20. When matching a repeated Unicode property with a minimum greater than zero,
  +    (for example \pL{2,}), PCRE could look past the end of the subject if it
  +    reached it while seeking the minimum number of characters. This could
  +    happen only if some of the characters were more than one byte long, because
  +    there is a check for at least the minimum number of bytes.
  +
  +21. Refactored the implementation of \p and \P so as to be more general, to
  +    allow for more different types of property in future. This has changed the
  +    compiled form incompatibly. Anybody with saved compiled patterns that use
  +    \p or \P will have to recompile them.
  +
  +22. Added "Any" and "L&" to the supported property types.
  +
  +23. Recognize \x{...} as a code point specifier, even when not in UTF-8 mode,
  +    but give a compile time error if the value is greater than 0xff.
  +
  +24. The man pages for pcrepartial, pcreprecompile, and pcre_compile2 were
  +    accidentally not being installed or uninstalled.
  +
  +25. The pcre.h file was built from pcre.h.in, but the only changes that were
  +    made were to insert the current release number. This seemed silly, because
  +    it made things harder for people building PCRE on systems that don't run
  +    "configure". I have turned pcre.h into a distributed file, no longer built
  +    by "configure", with the version identification directly included. There is
  +    no longer a pcre.h.in file.
  +
  +    However, this change necessitated a change to the pcre-config script as
  +    well. It is built from pcre-config.in, and one of the substitutions was the
  +    release number. I have updated configure.ac so that ./configure now finds
  +    the release number by grepping pcre.h.
  +
  +26. Added the ability to run the tests under valgrind.
  +
  +
  +Version 6.4 05-Sep-05
  +---------------------
  +
  + 1. Change 6.0/10/(l) to pcregrep introduced a bug that caused separator lines
  +    "--" to be printed when multiple files were scanned, even when none of the
  +    -A, -B, or -C options were used. This is not compatible with Gnu grep, so I
  +    consider it to be a bug, and have restored the previous behaviour.
  +
  + 2. A couple of code tidies to get rid of compiler warnings.
  +
  + 3. The pcretest program used to cheat by referring to symbols in the library
  +    whose names begin with _pcre_. These are internal symbols that are not
  +    really supposed to be visible externally, and in some environments it is
  +    possible to suppress them. The cheating is now confined to including
  +    certain files from the library's source, which is a bit cleaner.
  +
  + 4. Renamed pcre.in as pcre.h.in to go with pcrecpp.h.in; it also makes the
  +    file's purpose clearer.
  +
  + 5. Reorganized pcre_ucp_findchar().
  +
  +
  +Version 6.3 15-Aug-05
  +---------------------
  +
  + 1. The file libpcre.pc.in did not have general read permission in the tarball.
  +
  + 2. There were some problems when building without C++ support:
  +
  +    (a) If C++ support was not built, "make install" and "make test" still
  +        tried to test it.
  +
  +    (b) There were problems when the value of CXX was explicitly set. Some
  +        changes have been made to try to fix these, and ...
  +
  +    (c) --disable-cpp can now be used to explicitly disable C++ support.
  +
  +    (d) The use of @CPP_OBJ@ directly caused a blank line preceded by a
  +        backslash in a target when C++ was disabled. This confuses some
  +        versions of "make", apparently. Using an intermediate variable solves
  +        this. (Same for CPP_LOBJ.)
  +
  + 3. $(LINK_FOR_BUILD) now includes $(CFLAGS_FOR_BUILD) and $(LINK)
  +    (non-Windows) now includes $(CFLAGS) because these flags are sometimes
  +    necessary on certain architectures.
  +
  + 4. Added a setting of -export-symbols-regex to the link command to remove
  +    those symbols that are exported in the C sense, but actually are local
  +    within the library, and not documented. Their names all begin with
  +    "_pcre_". This is not a perfect job, because (a) we have to except some
  +    symbols that pcretest ("illegally") uses, and (b) the facility isn't always
  +    available (and never for static libraries). I have made a note to try to
  +    find a way round (a) in the future.
  +
  +
   Version 6.2 01-Aug-05
   ---------------------



  Index: LICENCE
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/LICENCE,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LICENCE    15 Jun 2005 08:57:10 -0000    1.2
  +++ LICENCE    7 Nov 2006 16:50:36 -0000    1.3
  @@ -22,7 +22,7 @@
   University of Cambridge Computing Service,
   Cambridge, England. Phone: +44 1223 334714.


-Copyright (c) 1997-2005 University of Cambridge
+Copyright (c) 1997-2006 University of Cambridge
All rights reserved.


@@ -31,7 +31,7 @@

Contributed by: Google Inc.

-Copyright (c) 2005, Google Inc.
+Copyright (c) 2006, Google Inc.
All rights reserved.



  Index: Makefile
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/Makefile,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Makefile    3 Oct 2005 09:56:42 -0000    1.5
  +++ Makefile    7 Nov 2006 16:50:36 -0000    1.6
  @@ -1,4 +1,4 @@
  -# $Cambridge: exim/exim-src/src/pcre/Makefile,v 1.5 2005/10/03 09:56:42 ph10 Exp $
  +# $Cambridge: exim/exim-src/src/pcre/Makefile,v 1.6 2006/11/07 16:50:36 ph10 Exp $


# Makefile for PCRE (Perl-Compatible Regular Expression) library for use by
# Exim. This is a tailored Makefile, not the normal one that comes with the
@@ -14,7 +14,7 @@
##############################################################################

   OBJ = pcre_maketables.o chartables.o pcre_fullinfo.o pcre_get.o \
  -      pcre_globals.o pcre_compile.o pcre_config.o pcre_exec.o pcre_printint.o \
  +      pcre_globals.o pcre_compile.o pcre_config.o pcre_exec.o \
         pcre_study.o pcre_tables.o pcre_try_flipped.o pcre_version.o


   all:            libpcre.a ../pcretest
  @@ -60,10 +60,6 @@
   pcre_globals.o: pcre_globals.c pcre.h config.h pcre_internal.h Makefile
           @echo "$(CC) pcre_globals.c"
           $(FE)$(CC) -c $(CFLAGS) pcre_globals.c
  -
  -pcre_printint.o: pcre_printint.c pcre.h config.h pcre_internal.h Makefile
  -        @echo "$(CC) pcre_printint.c"
  -        $(FE)$(CC) -c $(CFLAGS) pcre_printint.c


   pcre_study.o:   pcre_study.c pcre.h config.h pcre_internal.h Makefile
           @echo "$(CC) pcre_study.c"


  Index: config.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/config.h,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- config.h    7 Oct 2004 13:04:13 -0000    1.1
  +++ config.h    7 Nov 2006 16:50:36 -0000    1.2
  @@ -1,11 +1,11 @@
  -/* $Cambridge: exim/exim-src/src/pcre/config.h,v 1.1 2004/10/07 13:04:13 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/config.h,v 1.2 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *           config.h for PCRE for Exim           *
   *************************************************/


/* The PCRE sources include config.h, which for a free-standing PCRE build gets
-set up by autoconf. For the embedded version in Exim, this file, which is
+set up by autoconf. For the embedded version in Exim, this file, which is
manually maintained, is used.

The only configuration thing that matters for the PCRE library itself is
@@ -14,21 +14,26 @@
HAVE_MEMMOVE to 1 in config.h when memmove() is present. If that is not set, it
defines memmove() as a macro for bcopy().

-Exim works differently. It handles this case by defining memmove() as a macro
-in its os.h-SunOS4 file. We interface this to PCRE by including the os.h file
-here, and then defining HAVE_MEMOVE so that PCRE's code in internal.h leaves
+Exim works differently. It handles this case by defining memmove() as a macro
+in its os.h-SunOS4 file. We interface this to PCRE by including the os.h file
+here, and then defining HAVE_MEMOVE so that PCRE's code in internal.h leaves
things alone. */

#include "../os.h"
#define HAVE_MEMMOVE 1

-/* We also set up directly a number of parameters that, in the freestanding
+/* We also set up directly a number of parameters that, in the freestanding
PCRE, can be adjusted by "configure". */

   #define NEWLINE                 '\n'
   #define LINK_SIZE               2
   #define MATCH_LIMIT             10000000
  +#define MATCH_LIMIT_RECURSION   10000000
   #define POSIX_MALLOC_THRESHOLD  10
  +
  +#define MAX_NAME_SIZE           32
  +#define MAX_NAME_COUNT          10000
  +#define MAX_DUPLENGTH           30000


/* There is some stuff in the PCRE sources for compilation on non-Unix systems
and non-ASCII systems. For Exim's purposes, just flatten it all. */

  Index: dftables.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/dftables.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- dftables.c    8 Aug 2005 10:22:14 -0000    1.3
  +++ dftables.c    7 Nov 2006 16:50:36 -0000    1.4
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/dftables.c,v 1.3 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/dftables.c,v 1.4 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without

  Index: pcre.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- pcre.h    8 Aug 2005 10:22:14 -0000    1.3
  +++ pcre.h    7 Nov 2006 16:50:36 -0000    1.4
  @@ -1,9 +1,11 @@
  +/* $Cambridge: exim/exim-src/src/pcre/pcre.h,v 1.4 2006/11/07 16:50:36 ph10 Exp $ */
  +
   /*************************************************
   *       Perl-Compatible Regular Expressions      *
   *************************************************/


-/* In its original form, this is the .in file that is transformed by
-"configure" into pcre.h.
+/* This is the public header file for the PCRE library, to be #included by
+applications that call the PCRE functions.

              Copyright (c) 1997-2005 University of Cambridge


@@ -39,14 +41,26 @@
#ifndef _PCRE_H
#define _PCRE_H

-/* The file pcre.h is build by "configure". Do not edit it; instead
-make changes to pcre.in. */
+/* The current PCRE version information. */
+
+/* NOTES FOR FUTURE MAINTAINERS: Do not use numbers with leading zeros, because
+they may be treated as octal constants. The PCRE_PRERELEASE feature is for
+identifying release candidates. It might be defined as -RC2, for example. In
+real releases, it should be defined empty. Do not change the alignment of these
+statments. The code in ./configure greps out the version numbers by using "cut"
+to get values from column 29 onwards. These are substituted into pcre-config
+and libpcre.pc. The values are not put into configure.ac and substituted here
+(which would simplify this issue) because that makes life harder for those who
+cannot run ./configure. As it now stands, this file need not be edited in that
+circumstance. */

   #define PCRE_MAJOR          6
  -#define PCRE_MINOR          2
  -#define PCRE_DATE           01-Aug-2005
  +#define PCRE_MINOR          7
  +#define PCRE_PRERELEASE
  +#define PCRE_DATE           04-Jul-2006


-/* Win32 uses DLL by default; it needs special stuff for exported functions. */
+/* Win32 uses DLL by default; it needs special stuff for exported functions
+when building PCRE. */

#ifdef _WIN32
# ifdef PCRE_DEFINITION
@@ -60,7 +74,7 @@
# endif
#endif

-/* For other operating systems, we use the standard "extern". */
+/* Otherwise, we use the standard "extern". */

   #ifndef PCRE_DATA_SCOPE
   #  ifdef __cplusplus
  @@ -102,6 +116,10 @@
   #define PCRE_DFA_SHORTEST       0x00010000
   #define PCRE_DFA_RESTART        0x00020000
   #define PCRE_FIRSTLINE          0x00040000
  +#define PCRE_DUPNAMES           0x00080000
  +#define PCRE_NEWLINE_CR         0x00100000
  +#define PCRE_NEWLINE_LF         0x00200000
  +#define PCRE_NEWLINE_CRLF       0x00300000


/* Exec-time and get/set-time error codes */

  @@ -125,6 +143,7 @@
   #define PCRE_ERROR_DFA_UMLIMIT    (-18)
   #define PCRE_ERROR_DFA_WSSIZE     (-19)
   #define PCRE_ERROR_DFA_RECURSE    (-20)
  +#define PCRE_ERROR_RECURSIONLIMIT (-21)


/* Request types for pcre_fullinfo() */

  @@ -142,7 +161,8 @@
   #define PCRE_INFO_STUDYSIZE         10
   #define PCRE_INFO_DEFAULT_TABLES    11


-/* Request types for pcre_config() */
+/* Request types for pcre_config(). Do not re-arrange, in order to remain
+compatible. */

   #define PCRE_CONFIG_UTF8                    0
   #define PCRE_CONFIG_NEWLINE                 1
  @@ -151,19 +171,30 @@
   #define PCRE_CONFIG_MATCH_LIMIT             4
   #define PCRE_CONFIG_STACKRECURSE            5
   #define PCRE_CONFIG_UNICODE_PROPERTIES      6
  +#define PCRE_CONFIG_MATCH_LIMIT_RECURSION   7


-/* Bit flags for the pcre_extra structure */
+/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine
+these bits, just add new ones on the end, in order to remain compatible. */

  -#define PCRE_EXTRA_STUDY_DATA          0x0001
  -#define PCRE_EXTRA_MATCH_LIMIT         0x0002
  -#define PCRE_EXTRA_CALLOUT_DATA        0x0004
  -#define PCRE_EXTRA_TABLES              0x0008
  +#define PCRE_EXTRA_STUDY_DATA             0x0001
  +#define PCRE_EXTRA_MATCH_LIMIT            0x0002
  +#define PCRE_EXTRA_CALLOUT_DATA           0x0004
  +#define PCRE_EXTRA_TABLES                 0x0008
  +#define PCRE_EXTRA_MATCH_LIMIT_RECURSION  0x0010


/* Types */

   struct real_pcre;                 /* declaration; the definition is private  */
   typedef struct real_pcre pcre;


  +/* When PCRE is compiled as a C++ library, the subject pointer type can be
  +replaced with a custom type. For conventional use, the public interface is a
  +const char *. */
  +
  +#ifndef PCRE_SPTR
  +#define PCRE_SPTR const char *
  +#endif
  +
   /* The structure for passing additional data to pcre_exec(). This is defined in
   such as way as to be extensible. Always add new fields at the end, in order to
   remain compatible. */
  @@ -174,6 +205,7 @@
     unsigned long int match_limit;  /* Maximum number of calls to match() */
     void *callout_data;             /* Data passed back in callouts */
     const unsigned char *tables;    /* Pointer to character tables */
  +  unsigned long int match_limit_recursion; /* Max recursive calls to match() */
   } pcre_extra;


   /* The structure for passing out data via the pcre_callout_function. We use a
  @@ -186,7 +218,7 @@
     /* ------------------------ Version 0 ------------------------------- */
     int          callout_number;    /* Number compiled into pattern */
     int         *offset_vector;     /* The offset vector */
  -  const char  *subject;           /* The subject being matched */
  +  PCRE_SPTR    subject;           /* The subject being matched */
     int          subject_length;    /* The length of the subject */
     int          start_match;       /* Offset to start of this match attempt */
     int          current_position;  /* Where we currently are in the subject */
  @@ -232,7 +264,7 @@
                     int);
   PCRE_DATA_SCOPE int  pcre_dfa_exec(const pcre *, const pcre_extra *,
                     const char *, int, int, int, int *, int , int *, int);
  -PCRE_DATA_SCOPE int  pcre_exec(const pcre *, const pcre_extra *, const char *,
  +PCRE_DATA_SCOPE int  pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
                      int, int, int, int *, int);
   PCRE_DATA_SCOPE void pcre_free_substring(const char *);
   PCRE_DATA_SCOPE void pcre_free_substring_list(const char **);
  @@ -241,6 +273,8 @@
   PCRE_DATA_SCOPE int  pcre_get_named_substring(const pcre *, const char *,
                     int *, int, const char *, const char **);
   PCRE_DATA_SCOPE int  pcre_get_stringnumber(const pcre *, const char *);
  +PCRE_DATA_SCOPE int  pcre_get_stringtable_entries(const pcre *, const char *,
  +                  char **, char **);
   PCRE_DATA_SCOPE int  pcre_get_substring(const char *, int *, int, int,
                     const char **);
   PCRE_DATA_SCOPE int  pcre_get_substring_list(const char *, int *, int,


  Index: pcre_compile.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_compile.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_compile.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_compile.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_compile.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_compile.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -44,9 +44,19 @@
supporting internal functions that are not used by other modules. */


  +#define NLBLOCK cd            /* The block containing newline information */
   #include "pcre_internal.h"



  +/* When DEBUG is defined, we need the pcre_printint() function, which is also
  +used by pcretest. DEBUG is not defined when building a production library. */
  +
  +#ifdef DEBUG
  +#include "pcre_printint.src"
  +#endif
  +
  +
  +
   /*************************************************
   *      Code parameters and static tables         *
   *************************************************/
  @@ -109,7 +119,7 @@



/* 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,
+terminated by a zero length entry. The first three must be alpha, lower, upper,
as this is assumed for handling case independence. */

   static const char *const posix_names[] = {
  @@ -120,25 +130,31 @@
   static const uschar posix_name_lengths[] = {
     5, 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. The table for [:blank:] is dynamically modified to remove
-the vertical space characters. */
+/* Table of class bit maps for each POSIX class. Each class is formed from a
+base map, with an optional addition or removal of another map. Then, for some
+classes, there is some additional tweaking: for [:blank:] the vertical space
+characters are removed, and for [:alpha:] and [:alnum:] the underscore
+character is removed. The triples in the table consist of the base map offset,
+second map offset or -1 if no second map, and a non-negative value for map
+addition or a negative value for map subtraction (if there are two maps). The
+absolute value of the third field has these meanings: 0 => no tweaking, 1 =>
+remove vertical space characters, 2 => remove underscore. */

   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_space, -1,         -1,             /* blank - a GNU extension */
  -  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 - a Perl extension */
  -  cbit_xdigit,-1,         -1              /* xdigit */
  +  cbit_word,  cbit_digit, -2,             /* alpha */
  +  cbit_lower, -1,          0,             /* lower */
  +  cbit_upper, -1,          0,             /* upper */
  +  cbit_word,  -1,          2,             /* alnum - word without underscore */
  +  cbit_print, cbit_cntrl,  0,             /* ascii */
  +  cbit_space, -1,          1,             /* blank - a GNU extension */
  +  cbit_cntrl, -1,          0,             /* cntrl */
  +  cbit_digit, -1,          0,             /* digit */
  +  cbit_graph, -1,          0,             /* graph */
  +  cbit_print, -1,          0,             /* print */
  +  cbit_punct, -1,          0,             /* punct */
  +  cbit_space, -1,          0,             /* space */
  +  cbit_word,  -1,          0,             /* word - a Perl extension */
  +  cbit_xdigit,-1,          0              /* xdigit */
   };



  @@ -177,7 +193,7 @@
     "unrecognized character after (?<",
     /* 25 */
     "lookbehind assertion is not fixed length",
  -  "malformed number after (?(",
  +  "malformed number or name after (?(",
     "conditional group contains more than two branches",
     "assertion expected after (?(",
     "(?R or (?digits must be followed by )",
  @@ -197,12 +213,17 @@
     "recursive call could loop indefinitely",
     "unrecognized character after (?P",
     "syntax error after (?P",
  -  "two named groups have the same name",
  +  "two named subpatterns have the same name",
     "invalid UTF-8 string",
     /* 45 */
     "support for \\P, \\p, and \\X has not been compiled",
     "malformed \\P or \\p sequence",
  -  "unknown property name after \\P or \\p"
  +  "unknown property name after \\P or \\p",
  +  "subpattern name is too long (maximum 32 characters)",
  +  "too many named subpatterns (maximum 10,000)",
  +  /* 50 */
  +  "repeated subpattern is too long",
  +  "octal value is greater than \\377 (not in UTF-8 mode)"
   };



  @@ -364,12 +385,15 @@
   check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount,
     int options, BOOL isclass)
   {
  -const uschar *ptr = *ptrptr;
  +BOOL utf8 = (options & PCRE_UTF8) != 0;
  +const uschar *ptr = *ptrptr + 1;
   int c, i;


  +GETCHARINCTEST(c, ptr);           /* Get character value, increment pointer */
  +ptr--;                            /* Set pointer back to the last byte */
  +
   /* If backslash is at the end of the pattern, it's an error. */


-c = *(++ptr);
if (c == 0) *errorcodeptr = ERR1;

   /* Non-alphamerics are literals. For digits or letters, do an initial lookup in
  @@ -444,49 +468,56 @@
         }


       /* \0 always starts an octal number, but we may drop through to here with a
  -    larger first octal digit. */
  +    larger first octal digit. The original code used just to take the least
  +    significant 8 bits of octal numbers (I think this is what early Perls used
  +    to do). Nowadays we allow for larger numbers in UTF-8 mode, but no more
  +    than 3 octal digits. */


       case '0':
       c -= '0';
       while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7')
           c = c * 8 + *(++ptr) - '0';
  -    c &= 255;     /* Take least significant 8 bits */
  +    if (!utf8 && c > 255) *errorcodeptr = ERR51;
       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. */
  +    /* \x is complicated. \x{ddd} is a character number which can be greater
  +    than 0xff in utf8 mode, but only if the ddd are hex digits. If not, { is
  +    treated as a data character. */


       case 'x':
  -#ifdef SUPPORT_UTF8
  -    if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
  +    if (ptr[1] == '{')
         {
         const uschar *pt = ptr + 2;
  -      register int count = 0;
  +      int count = 0;
  +
         c = 0;
         while ((digitab[*pt] & ctype_xdigit) != 0)
           {
  -        int cc = *pt++;
  +        register int cc = *pt++;
  +        if (c == 0 && cc == '0') continue;     /* Leading zeroes */
           count++;
  +
   #if !EBCDIC    /* ASCII coding */
           if (cc >= 'a') cc -= 32;               /* Convert to upper case */
  -        c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10));
  +        c = (c << 4) + cc - ((cc < 'A')? '0' : ('A' - 10));
   #else          /* EBCDIC coding */
           if (cc >= 'a' && cc <= 'z') cc += 64;  /* Convert to upper case */
  -        c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10));
  +        c = (c << 4) + cc - ((cc >= '0')? '0' : ('A' - 10));
   #endif
           }
  +
         if (*pt == '}')
           {
  -        if (c < 0 || count > 8) *errorcodeptr = ERR34;
  +        if (c < 0 || count > (utf8? 8 : 2)) *errorcodeptr = 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. */
         }
  -#endif


  -    /* Read just a single hex char */
  +    /* Read just a single-byte hex-defined char */


       c = 0;
       while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0)
  @@ -562,25 +593,26 @@
   Argument:
     ptrptr         points to the pattern position pointer
     negptr         points to a boolean that is set TRUE for negation else FALSE
  +  dptr           points to an int that is set to the detailed property value
     errorcodeptr   points to the error code variable


  -Returns:     value from ucp_type_table, or -1 for an invalid type
  +Returns:         type value from ucp_type_table, or -1 for an invalid type
   */


static int
-get_ucp(const uschar **ptrptr, BOOL *negptr, int *errorcodeptr)
+get_ucp(const uschar **ptrptr, BOOL *negptr, int *dptr, int *errorcodeptr)
{
int c, i, bot, top;
const uschar *ptr = *ptrptr;
-char name[4];
+char name[32];

c = *(++ptr);
if (c == 0) goto ERROR_RETURN;

*negptr = FALSE;

-/* \P or \p can be followed by a one- or two-character name in {}, optionally
-preceded by ^ for negation. */
+/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
+negation. */

   if (c == '{')
     {
  @@ -589,18 +621,14 @@
       *negptr = TRUE;
       ptr++;
       }
  -  for (i = 0; i <= 2; i++)
  +  for (i = 0; i < sizeof(name) - 1; i++)
       {
       c = *(++ptr);
       if (c == 0) goto ERROR_RETURN;
       if (c == '}') break;
       name[i] = c;
       }
  -  if (c !='}')   /* Try to distinguish error cases */
  -    {
  -    while (*(++ptr) != 0 && *ptr != '}');
  -    if (*ptr == '}') goto UNKNOWN_RETURN; else goto ERROR_RETURN;
  -    }
  +  if (c !='}') goto ERROR_RETURN;
     name[i] = 0;
     }


@@ -621,13 +649,16 @@

   while (bot < top)
     {
  -  i = (bot + top)/2;
  +  i = (bot + top) >> 1;
     c = strcmp(name, _pcre_utt[i].name);
  -  if (c == 0) return _pcre_utt[i].value;
  +  if (c == 0)
  +    {
  +    *dptr = _pcre_utt[i].value;
  +    return _pcre_utt[i].type;
  +    }
     if (c > 0) bot = i + 1; else top = i;
     }


-UNKNOWN_RETURN:
*errorcodeptr = ERR47;
*ptrptr = ptr;
return -1;
@@ -743,6 +774,49 @@


   /*************************************************
  +*     Find forward referenced named subpattern   *
  +*************************************************/
  +
  +/* This function scans along a pattern looking for capturing subpatterns, and
  +counting them. If it finds a named pattern that matches the name it is given,
  +it returns its number. This is used for forward references to named
  +subpatterns. We know that if (?P< is encountered, the name will be terminated
  +by '>' because that is checked in the first pass.
  +
  +Arguments:
  +  pointer      current position in the pattern
  +  count        current count of capturing parens
  +  name         name to seek
  +  namelen      name length
  +
  +Returns:       the number of the named subpattern, or -1 if not found
  +*/
  +
  +static int
  +find_named_parens(const uschar *ptr, int count, const uschar *name, int namelen)
  +{
  +const uschar *thisname;
  +for (; *ptr != 0; ptr++)
  +  {
  +  if (*ptr == '\\' && ptr[1] != 0) { ptr++; continue; }
  +  if (*ptr != '(') continue;
  +  if (ptr[1] != '?') { count++; continue; }
  +  if (ptr[2] == '(') { ptr += 2; continue; }
  +  if (ptr[2] != 'P' || ptr[3] != '<') continue;
  +  count++;
  +  ptr += 4;
  +  thisname = ptr;
  +  while (*ptr != '>') ptr++;
  +  if (namelen == ptr - thisname &&
  +      strncmp((char *)name, (char*)thisname, namelen) == 0)
  +    return count;
  +  }
  +return -1;
  +}
  +
  +
  +
  +/*************************************************
   *      Find first significant op code            *
   *************************************************/


@@ -897,6 +971,7 @@

       case OP_CHAR:
       case OP_CHARNC:
  +    case OP_NOT:
       branchlength++;
       cc += 2;
   #ifdef SUPPORT_UTF8
  @@ -930,7 +1005,7 @@


       case OP_PROP:
       case OP_NOTPROP:
  -    cc++;
  +    cc += 2;
       /* Fall through */


       case OP_NOT_DIGIT:
  @@ -1011,14 +1086,19 @@
   static const uschar *
   find_bracket(const uschar *code, BOOL utf8, int number)
   {
  -#ifndef SUPPORT_UTF8
  -utf8 = utf8;               /* Stop pedantic compilers complaining */
  -#endif
  -
   for (;;)
     {
     register int c = *code;
     if (c == OP_END) return NULL;
  +
  +  /* XCLASS is used for classes that cannot be represented just by a bit
  +  map. This includes negated single high-valued characters. The length in
  +  the table is zero; the actual length is stored in the compiled code. */
  +
  +  if (c == OP_XCLASS) code += GET(code, 1);
  +
  +  /* Handle bracketed group */
  +
     else if (c > OP_BRA)
       {
       int n = c - OP_BRA;
  @@ -1026,17 +1106,16 @@
       if (n == number) return (uschar *)code;
       code += _pcre_OP_lengths[OP_BRA];
       }
  +
  +  /* Otherwise, we get the item's length from the table. In UTF-8 mode, opcodes
  +  that are followed by a character may be followed by a multi-byte character.
  +  The length in the table is a minimum, so we have to scan along to skip the
  +  extra bytes. All opcodes are less than 128, so we can use relatively
  +  efficient code. */
  +
     else
       {
       code += _pcre_OP_lengths[c];
  -
  -#ifdef SUPPORT_UTF8
  -
  -    /* In UTF-8 mode, opcodes that are followed by a character may be followed
  -    by a multi-byte character. The length in the table is a minimum, so we have
  -    to scan along to skip the extra bytes. All opcodes are less than 128, so we
  -    can use relatively efficient code. */
  -
       if (utf8) switch(c)
         {
         case OP_CHAR:
  @@ -1052,16 +1131,7 @@
         case OP_MINQUERY:
         while ((*code & 0xc0) == 0x80) code++;
         break;
  -
  -      /* XCLASS is used for classes that cannot be represented just by a bit
  -      map. This includes negated single high-valued characters. The length in
  -      the table is zero; the actual length is stored in the compiled code. */
  -
  -      case OP_XCLASS:
  -      code += GET(code, 1) + 1;
  -      break;
         }
  -#endif
       }
     }
   }
  @@ -1085,30 +1155,34 @@
   static const uschar *
   find_recurse(const uschar *code, BOOL utf8)
   {
  -#ifndef SUPPORT_UTF8
  -utf8 = utf8;               /* Stop pedantic compilers complaining */
  -#endif
  -
   for (;;)
     {
     register int c = *code;
     if (c == OP_END) return NULL;
  -  else if (c == OP_RECURSE) return code;
  +  if (c == OP_RECURSE) return code;
  +
  +  /* XCLASS is used for classes that cannot be represented just by a bit
  +  map. This includes negated single high-valued characters. The length in
  +  the table is zero; the actual length is stored in the compiled code. */
  +
  +  if (c == OP_XCLASS) code += GET(code, 1);
  +
  +  /* All bracketed groups have the same length. */
  +
     else if (c > OP_BRA)
       {
       code += _pcre_OP_lengths[OP_BRA];
       }
  +
  +  /* Otherwise, we get the item's length from the table. In UTF-8 mode, opcodes
  +  that are followed by a character may be followed by a multi-byte character.
  +  The length in the table is a minimum, so we have to scan along to skip the
  +  extra bytes. All opcodes are less than 128, so we can use relatively
  +  efficient code. */
  +
     else
       {
       code += _pcre_OP_lengths[c];
  -
  -#ifdef SUPPORT_UTF8
  -
  -    /* In UTF-8 mode, opcodes that are followed by a character may be followed
  -    by a multi-byte character. The length in the table is a minimum, so we have
  -    to scan along to skip the extra bytes. All opcodes are less than 128, so we
  -    can use relatively efficient code. */
  -
       if (utf8) switch(c)
         {
         case OP_CHAR:
  @@ -1124,16 +1198,7 @@
         case OP_MINQUERY:
         while ((*code & 0xc0) == 0x80) code++;
         break;
  -
  -      /* XCLASS is used for classes that cannot be represented just by a bit
  -      map. This includes negated single high-valued characters. The length in
  -      the table is zero; the actual length is stored in the compiled code. */
  -
  -      case OP_XCLASS:
  -      code += GET(code, 1) + 1;
  -      break;
         }
  -#endif
       }
     }
   }
  @@ -1490,13 +1555,10 @@
   static BOOL
   get_othercase_range(int *cptr, int d, int *ocptr, int *odptr)
   {
  -int c, chartype, othercase, next;
  +int c, othercase, next;


   for (c = *cptr; c <= d; c++)
  -  {
  -  if (_pcre_ucp_findchar(c, &chartype, &othercase) == ucp_L && othercase != 0)
  -    break;
  -  }
  +  { if ((othercase = _pcre_ucp_othercase(c)) >= 0) break; }


if (c > d) return FALSE;

@@ -1505,9 +1567,7 @@

   for (++c; c <= d; c++)
     {
  -  if (_pcre_ucp_findchar(c, &chartype, &othercase) != ucp_L ||
  -        othercase != next)
  -    break;
  +  if (_pcre_ucp_othercase(c) != next) break;
     next++;
     }


  @@ -1554,7 +1614,6 @@
   int firstbyte, reqbyte;
   int zeroreqbyte, zerofirstbyte;
   int req_caseopt, reqvary, tempreqvary;
  -int condcount = 0;
   int options = *optionsptr;
   int after_manual_callout = 0;
   register int c;
  @@ -1668,10 +1727,14 @@
       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 != NEWLINE) ;
  -      if (c != 0) continue;   /* Else fall through to handle end of string */
  +      while (*(++ptr) != 0) if (IS_NEWLINE(ptr)) break;
  +      if (*ptr != 0)
  +        {
  +        ptr += cd->nllen - 1;
  +        continue;
  +        }
  +      /* Else fall through to handle end of string */
  +      c = 0;
         }
       }


  @@ -1724,11 +1787,11 @@
       *code++ = OP_ANY;
       break;


  -    /* Character classes. If the included characters are all < 255 in value, we
  -    build a 32-byte bitmap of the permitted characters, except in the special
  -    case where there is only one such character. For negated classes, we build
  -    the map as usual, then invert it at the end. However, we use a different
  -    opcode so that data characters > 255 can be handled correctly.
  +    /* Character classes. If the included characters are all < 256, we build a
  +    32-byte bitmap of the permitted characters, except in the special case
  +    where there is only one such character. For negated classes, we build the
  +    map as usual, then invert it at the end. However, we use a different opcode
  +    so that data characters > 255 can be handled correctly.


       If the class contains characters outside the 0-255 range, a different
       opcode is compiled. It may optionally have a bit map for characters < 256,
  @@ -1819,8 +1882,9 @@
             check_posix_syntax(ptr, &tempptr, cd))
           {
           BOOL local_negate = FALSE;
  -        int posix_class, i;
  +        int posix_class, taboffset, tabopt;
           register const uschar *cbits = cd->cbits;
  +        uschar pbits[32];


           if (ptr[1] != ':')
             {
  @@ -1849,32 +1913,46 @@
           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. The [:blank:] class sets up the same
  -        chars as the [:space:] class (all white space). We remove the vertical
  -        white space chars afterwards. */
  +        /* We build the bit map for the POSIX class in a chunk of local store
  +        because we may be adding and subtracting from it, and we don't want to
  +        subtract bits that may be in the main map already. At the end we or the
  +        result into the bit map that is being built. */


           posix_class *= 3;
  -        for (i = 0; i < 3; i++)
  +
  +        /* Copy in the first table (always present) */
  +
  +        memcpy(pbits, cbits + posix_class_maps[posix_class],
  +          32 * sizeof(uschar));
  +
  +        /* If there is a second table, add or remove it as required. */
  +
  +        taboffset = posix_class_maps[posix_class + 1];
  +        tabopt = posix_class_maps[posix_class + 2];
  +
  +        if (taboffset >= 0)
             {
  -          BOOL blankclass = strncmp((char *)ptr, "blank", 5) == 0;
  -          int taboffset = posix_class_maps[posix_class + i];
  -          if (taboffset < 0) break;
  -          if (local_negate)
  -            {
  -            if (i == 0)
  -              for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+taboffset];
  -            else
  -              for (c = 0; c < 32; c++) classbits[c] &= ~cbits[c+taboffset];
  -            if (blankclass) classbits[1] |= 0x3c;
  -            }
  +          if (tabopt >= 0)
  +            for (c = 0; c < 32; c++) pbits[c] |= cbits[c + taboffset];
             else
  -            {
  -            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+taboffset];
  -            if (blankclass) classbits[1] &= ~0x3c;
  -            }
  +            for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];
             }


  +        /* Not see if we need to remove any special characters. An option
  +        value of 1 removes vertical space and 2 removes underscore. */
  +
  +        if (tabopt < 0) tabopt = -tabopt;
  +        if (tabopt == 1) pbits[1] &= ~0x3c;
  +          else if (tabopt == 2) pbits[11] &= 0x7f;
  +
  +        /* Add the POSIX table or its complement into the main table that is
  +        being built and we are done. */
  +
  +        if (local_negate)
  +          for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c];
  +        else
  +          for (c = 0; c < 32; c++) classbits[c] |= pbits[c];
  +
           ptr = tempptr + 1;
           class_charcount = 10;  /* Set > 1; assumes more than 1 per class */
           continue;    /* End of POSIX syntax handling */
  @@ -1941,12 +2019,14 @@
               case ESC_P:
                 {
                 BOOL negated;
  -              int property = get_ucp(&ptr, &negated, errorcodeptr);
  -              if (property < 0) goto FAILED;
  +              int pdata;
  +              int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);
  +              if (ptype < 0) goto FAILED;
                 class_utf8 = TRUE;
                 *class_utf8data++ = ((-c == ESC_p) != negated)?
                   XCL_PROP : XCL_NOTPROP;
  -              *class_utf8data++ = property;
  +              *class_utf8data++ = ptype;
  +              *class_utf8data++ = pdata;
                 class_charcount -= 2;   /* Not a < 256 character */
                 }
               continue;
  @@ -2128,10 +2208,8 @@
   #ifdef SUPPORT_UCP
           if ((options & PCRE_CASELESS) != 0)
             {
  -          int chartype;
             int othercase;
  -          if (_pcre_ucp_findchar(c, &chartype, &othercase) >= 0 &&
  -               othercase > 0)
  +          if ((othercase = _pcre_ucp_othercase(c)) >= 0)
               {
               *class_utf8data++ = XCL_SINGLE;
               class_utf8data += _pcre_ord2utf8(othercase, class_utf8data);
  @@ -2416,13 +2494,17 @@
       else if (*previous < OP_EODN)
         {
         uschar *oldcode;
  -      int prop_type;
  +      int prop_type, prop_value;
         op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
         c = *previous;


         OUTPUT_SINGLE_REPEAT:
  -      prop_type = (*previous == OP_PROP || *previous == OP_NOTPROP)?
  -        previous[1] : -1;
  +      if (*previous == OP_PROP || *previous == OP_NOTPROP)
  +        {
  +        prop_type = previous[1];
  +        prop_value = previous[2];
  +        }
  +      else prop_type = prop_value = -1;


         oldcode = code;
         code = previous;                  /* Usually overwrite previous item */
  @@ -2483,7 +2565,7 @@


           /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
           we have to insert the character for the previous code. For a repeated
  -        Unicode property match, there is an extra byte that defines the
  +        Unicode property match, there are two extra bytes that define the
           required property. In UTF-8 mode, long characters have their length in
           c, with the 0x80 bit as a flag. */


  @@ -2499,7 +2581,11 @@
   #endif
               {
               *code++ = c;
  -            if (prop_type >= 0) *code++ = prop_type;
  +            if (prop_type >= 0)
  +              {
  +              *code++ = prop_type;
  +              *code++ = prop_value;
  +              }
               }
             *code++ = OP_STAR + repeat_type;
             }
  @@ -2518,7 +2604,11 @@
             else
   #endif
             *code++ = c;
  -          if (prop_type >= 0) *code++ = prop_type;
  +          if (prop_type >= 0)
  +            {
  +            *code++ = prop_type;
  +            *code++ = prop_value;
  +            }
             repeat_max -= repeat_min;
             *code++ = OP_UPTO + repeat_type;
             PUT2INC(code, 0, repeat_max);
  @@ -2537,11 +2627,15 @@
   #endif
         *code++ = c;


  -      /* For a repeated Unicode property match, there is an extra byte that
  -      defines the required property. */
  +      /* For a repeated Unicode property match, there are two extra bytes that
  +      define the required property. */


   #ifdef SUPPORT_UCP
  -      if (prop_type >= 0) *code++ = prop_type;
  +      if (prop_type >= 0)
  +        {
  +        *code++ = prop_type;
  +        *code++ = prop_value;
  +        }
   #endif
         }


  @@ -2805,37 +2899,91 @@
           case '(':
           bravalue = OP_COND;       /* Conditional group */


  -        /* Condition to test for recursion */
  +        /* A condition can be a number, referring to a numbered group, a name,
  +        referring to a named group, 'R', referring to recursion, or an
  +        assertion. There are two unfortunate ambiguities, caused by history.
  +        (a) 'R' can be the recursive thing or the name 'R', and (b) a number
  +        could be a name that consists of digits. In both cases, we look for a
  +        name first; if not found, we try the other cases. If the first
  +        character after (?( is a word character, we know the rest up to ) will
  +        also be word characters because the syntax was checked in the first
  +        pass. */


  -        if (ptr[1] == 'R')
  +        if ((cd->ctypes[ptr[1]] & ctype_word) != 0)
             {
  -          code[1+LINK_SIZE] = OP_CREF;
  -          PUT2(code, 2+LINK_SIZE, CREF_RECURSE);
  +          int i, namelen;
  +          int condref = 0;
  +          const uschar *name;
  +          uschar *slot = cd->name_table;
  +
  +          /* This is needed for all successful cases. */
  +
             skipbytes = 3;
  -          ptr += 3;
  -          }


  -        /* Condition to test for a numbered subpattern match. We know that
  -        if a digit follows ( then there will just be digits until ) because
  -        the syntax was checked in the first pass. */
  +          /* Read the name, but also get it as a number if it's all digits */


  -        else if ((digitab[ptr[1]] && ctype_digit) != 0)
  -          {
  -          int condref;                 /* Don't amalgamate; some compilers */
  -          condref = *(++ptr) - '0';    /* grumble at autoincrement in declaration */
  -          while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
  -          if (condref == 0)
  +          name = ++ptr;
  +          while (*ptr != ')')
               {
  -            *errorcodeptr = ERR35;
  -            goto FAILED;
  +            if (condref >= 0)
  +              condref = ((digitab[*ptr] & ctype_digit) != 0)?
  +                condref * 10 + *ptr - '0' : -1;
  +            ptr++;
               }
  +          namelen = ptr - name;
             ptr++;
  -          code[1+LINK_SIZE] = OP_CREF;
  -          PUT2(code, 2+LINK_SIZE, condref);
  -          skipbytes = 3;
  +
  +          for (i = 0; i < cd->names_found; i++)
  +            {
  +            if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break;
  +            slot += cd->name_entry_size;
  +            }
  +
  +          /* Found a previous named subpattern */
  +
  +          if (i < cd->names_found)
  +            {
  +            condref = GET2(slot, 0);
  +            code[1+LINK_SIZE] = OP_CREF;
  +            PUT2(code, 2+LINK_SIZE, condref);
  +            }
  +
  +          /* Search the pattern for a forward reference */
  +
  +          else if ((i = find_named_parens(ptr, *brackets, name, namelen)) > 0)
  +            {
  +            code[1+LINK_SIZE] = OP_CREF;
  +            PUT2(code, 2+LINK_SIZE, i);
  +            }
  +
  +          /* Check for 'R' for recursion */
  +
  +          else if (namelen == 1 && *name == 'R')
  +            {
  +            code[1+LINK_SIZE] = OP_CREF;
  +            PUT2(code, 2+LINK_SIZE, CREF_RECURSE);
  +            }
  +
  +          /* Check for a subpattern number */
  +
  +          else if (condref > 0)
  +            {
  +            code[1+LINK_SIZE] = OP_CREF;
  +            PUT2(code, 2+LINK_SIZE, condref);
  +            }
  +
  +          /* Either an unidentified subpattern, or a reference to (?(0) */
  +
  +          else
  +            {
  +            *errorcodeptr = (condref == 0)? ERR35: ERR15;
  +            goto FAILED;
  +            }
             }
  +
           /* For conditions that are assertions, we just fall through, having
           set bravalue above. */
  +
           break;


           case '=':                 /* Positive lookahead */
  @@ -2907,10 +3055,13 @@
                 {
                 if (slot[2+namelen] == 0)
                   {
  -                *errorcodeptr = ERR43;
  -                goto FAILED;
  +                if ((options & PCRE_DUPNAMES) == 0)
  +                  {
  +                  *errorcodeptr = ERR43;
  +                  goto FAILED;
  +                  }
                   }
  -              crc = -1;             /* Current name is substring */
  +              else crc = -1;      /* Current name is substring */
                 }
               if (crc < 0)
                 {
  @@ -2943,14 +3094,18 @@
               if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break;
               slot += cd->name_entry_size;
               }
  -          if (i >= cd->names_found)
  +
  +          if (i < cd->names_found)         /* Back reference */
  +            {
  +            recno = GET2(slot, 0);
  +            }
  +          else if ((recno =                /* Forward back reference */
  +                    find_named_parens(ptr, *brackets, name, namelen)) <= 0)
               {
               *errorcodeptr = ERR15;
               goto FAILED;
               }


  -          recno = GET2(slot, 0);
  -
             if (type == '>') goto HANDLE_RECURSION;  /* A few lines below */


             /* Back reference */
  @@ -2990,9 +3145,8 @@
             regex in case it doesn't exist. */


             *code = OP_END;
  -          called = (recno == 0)?
  -            cd->start_code : find_bracket(cd->start_code, utf8, recno);
  -
  +          called = (recno == 0)? cd->start_code :
  +            find_bracket(cd->start_code, utf8, recno);
             if (called == NULL)
               {
               *errorcodeptr = ERR15;
  @@ -3009,11 +3163,20 @@
               goto FAILED;
               }


  -          /* Insert the recursion/subroutine item */
  +          /* Insert the recursion/subroutine item, automatically wrapped inside
  +          "once" brackets. */
  +
  +          *code = OP_ONCE;
  +          PUT(code, 1, 2 + 2*LINK_SIZE);
  +          code += 1 + LINK_SIZE;


             *code = OP_RECURSE;
             PUT(code, 1, called - cd->start_code);
             code += 1 + LINK_SIZE;
  +
  +          *code = OP_KET;
  +          PUT(code, 1, 2 + 2*LINK_SIZE);
  +          code += 1 + LINK_SIZE;
             }
           continue;


  @@ -3030,6 +3193,7 @@
               case '-': optset = &unset; break;


               case 'i': *optset |= PCRE_CASELESS; break;
  +            case 'J': *optset |= PCRE_DUPNAMES; break;
               case 'm': *optset |= PCRE_MULTILINE; break;
               case 's': *optset |= PCRE_DOTALL; break;
               case 'x': *optset |= PCRE_EXTENDED; break;
  @@ -3146,7 +3310,7 @@
       else if (bravalue == OP_COND)
         {
         uschar *tc = code;
  -      condcount = 0;
  +      int condcount = 0;


         do {
            condcount++;
  @@ -3283,10 +3447,12 @@
         else if (-c == ESC_P || -c == ESC_p)
           {
           BOOL negated;
  -        int value = get_ucp(&ptr, &negated, errorcodeptr);
  +        int pdata;
  +        int ptype = get_ucp(&ptr, &negated, &pdata, errorcodeptr);
           previous = code;
           *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
  -        *code++ = value;
  +        *code++ = ptype;
  +        *code++ = pdata;
           }
   #endif


  @@ -3841,7 +4007,7 @@
                   with errorptr and erroroffset set
   */


  -EXPORT pcre *
  +PCRE_DATA_SCOPE pcre *
   pcre_compile(const char *pattern, int options, const char **errorptr,
     int *erroroffset, const unsigned char *tables)
   {
  @@ -3849,13 +4015,14 @@
   }



  -EXPORT pcre *
  +
  +PCRE_DATA_SCOPE pcre *
   pcre_compile2(const char *pattern, int options, int *errorcodeptr,
     const char **errorptr, int *erroroffset, const unsigned char *tables)
   {
   real_pcre *re;
   int length = 1 + LINK_SIZE;      /* For initial BRA plus length */
  -int c, firstbyte, reqbyte;
  +int c, firstbyte, reqbyte, newline;
   int bracount = 0;
   int branch_extra = 0;
   int branch_newextra;
  @@ -3876,6 +4043,7 @@
   const uschar *codestart;
   const uschar *ptr;
   compile_data compile_block;
  +compile_data *cd = &compile_block;
   int brastack[BRASTACK_SIZE];
   uschar bralenstack[BRASTACK_SIZE];


@@ -3929,18 +4097,42 @@
/* 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;
  +cd->lcc = tables + lcc_offset;
  +cd->fcc = tables + fcc_offset;
  +cd->cbits = tables + cbits_offset;
  +cd->ctypes = tables + ctypes_offset;
  +
  +/* Handle different types of newline. The two bits give four cases. The current
  +code allows for one- or two-byte sequences. */
  +
  +switch (options & PCRE_NEWLINE_CRLF)
  +  {
  +  default:              newline = NEWLINE; break;   /* Compile-time default */
  +  case PCRE_NEWLINE_CR: newline = '\r'; break;
  +  case PCRE_NEWLINE_LF: newline = '\n'; break;
  +  case PCRE_NEWLINE_CR+
  +       PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break;
  +  }
  +
  +if (newline > 255)
  +  {
  +  cd->nllen = 2;
  +  cd->nl[0] = (newline >> 8) & 255;
  +  cd->nl[1] = newline & 255;
  +  }
  +else
  +  {
  +  cd->nllen = 1;
  +  cd->nl[0] = newline;
  +  }


/* Maximum back reference and backref bitmap. This is updated for numeric
references during the first pass, but for named references during the actual
compile pass. The bitmap records up to 31 back references to help in deciding
whether (.*) can be treated as anchored or not. */

-compile_block.top_backref = 0;
-compile_block.backref_map = 0;
+cd->top_backref = 0;
+cd->backref_map = 0;

/* Reflect pattern for debugging output */

@@ -3974,14 +4166,16 @@

     if ((options & PCRE_EXTENDED) != 0)
       {
  -    if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
  +    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 != NEWLINE) ;
  -      if (c == 0) break;
  -      continue;
  +      while (*(++ptr) != 0) if (IS_NEWLINE(ptr)) break;
  +      if (*ptr != 0)
  +        {
  +        ptr += cd->nllen - 1;
  +        continue;
  +        }
  +      break;    /* End loop at end of pattern */
         }
       }


@@ -4042,15 +4236,17 @@
#endif

       /* \P and \p are for Unicode properties, but only when the support has
  -    been compiled. Each item needs 2 bytes. */
  +    been compiled. Each item needs 3 bytes. */


       else if (-c == ESC_P || -c == ESC_p)
         {
   #ifdef SUPPORT_UCP
         BOOL negated;
  -      length += 2;
  -      lastitemlength = 2;
  -      if (get_ucp(&ptr, &negated, &errorcode) < 0) goto PCRE_ERROR_RETURN;
  +      BOOL pdata;
  +      length += 3;
  +      lastitemlength = 3;
  +      if (get_ucp(&ptr, &negated, &pdata, &errorcode) < 0)
  +        goto PCRE_ERROR_RETURN;
         continue;
   #else
         errorcode = ERR45;
  @@ -4069,9 +4265,9 @@
       if (c <= -ESC_REF)
         {
         int refnum = -c - ESC_REF;
  -      compile_block.backref_map |= (refnum < 32)? (1 << refnum) : 1;
  -      if (refnum > compile_block.top_backref)
  -        compile_block.top_backref = refnum;
  +      cd->backref_map |= (refnum < 32)? (1 << refnum) : 1;
  +      if (refnum > cd->top_backref)
  +        cd->top_backref = refnum;
         length += 2;   /* For single back reference */
         if (ptr[1] == '{' && is_counted_repeat(ptr+2))
           {
  @@ -4216,7 +4412,7 @@
                 class_utf8 = TRUE;
                 length += LINK_SIZE + 2;
                 }
  -            length += 2;
  +            length += 3;
               }
   #endif
             }
  @@ -4225,7 +4421,9 @@
         /* Check the syntax for POSIX stuff. The bits we actually handle are
         checked during the real compile phase. */


  -      else if (*ptr == '[' && check_posix_syntax(ptr, &ptr, &compile_block))
  +      else if (*ptr == '[' &&
  +                (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
  +                check_posix_syntax(ptr, &ptr, cd))
           {
           ptr++;
           class_optcount = 10;    /* Make sure > 1 */
  @@ -4458,6 +4656,61 @@
           ptr += 2;
           break;


  +        /* Named subpatterns are an extension copied from Python */
  +
  +        case 'P':
  +        ptr += 3;
  +
  +        /* Handle the definition of a named subpattern */
  +
  +        if (*ptr == '<')
  +          {
  +          const uschar *p;    /* Don't amalgamate; some compilers */
  +          p = ++ptr;          /* grumble at autoincrement in declaration */
  +          while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
  +          if (*ptr != '>')
  +            {
  +            errorcode = ERR42;
  +            goto PCRE_ERROR_RETURN;
  +            }
  +          name_count++;
  +          if (name_count > MAX_NAME_COUNT)
  +            {
  +            errorcode = ERR49;
  +            goto PCRE_ERROR_RETURN;
  +            }
  +          if (ptr - p > max_name_size)
  +            {
  +            max_name_size = (ptr - p);
  +            if (max_name_size > MAX_NAME_SIZE)
  +              {
  +              errorcode = ERR48;
  +              goto PCRE_ERROR_RETURN;
  +              }
  +            }
  +          capturing = TRUE;   /* Named parentheses are always capturing */
  +          break;              /* Go handle capturing parentheses */
  +          }
  +
  +        /* Handle back references and recursive calls to named subpatterns */
  +
  +        if (*ptr == '=' || *ptr == '>')
  +          {
  +          length += 3 + 3*LINK_SIZE;  /* Allow for the automatic "once" */
  +          while ((cd->ctypes[*(++ptr)] & ctype_word) != 0);
  +          if (*ptr != ')')
  +            {
  +            errorcode = ERR42;
  +            goto PCRE_ERROR_RETURN;
  +            }
  +          goto RECURSE_CHECK_QUANTIFIED;
  +          }
  +
  +        /* Unknown character after (?P */
  +
  +        errorcode = ERR41;
  +        goto PCRE_ERROR_RETURN;
  +
           /* (?R) specifies a recursive call to the regex, which is an extension
           to provide the facility which can be obtained by (?p{perl-code}) in
           Perl 5.6. In Perl 5.8 this has become (??{perl-code}).
  @@ -4479,12 +4732,14 @@
             errorcode = ERR29;
             goto PCRE_ERROR_RETURN;
             }
  -        length += 1 + LINK_SIZE;
  +        length += 3 + 3*LINK_SIZE;  /* Allows for the automatic "once" */


           /* If this item is quantified, it will get wrapped inside brackets so
           as to use the code for quantified brackets. We jump down and use the
  -        code that handles this for real brackets. */
  +        code that handles this for real brackets. Come here from code for
  +        named recursions/subroutines. */


  +        RECURSE_CHECK_QUANTIFIED:
           if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{')
             {
             length += 2 + 2 * LINK_SIZE;       /* to make bracketed */
  @@ -4508,47 +4763,6 @@
           length += 2 + 2*LINK_SIZE;
           continue;


  -        /* Named subpatterns are an extension copied from Python */
  -
  -        case 'P':
  -        ptr += 3;
  -
  -        /* Handle the definition of a named subpattern */
  -
  -        if (*ptr == '<')
  -          {
  -          const uschar *p;    /* Don't amalgamate; some compilers */
  -          p = ++ptr;          /* grumble at autoincrement in declaration */
  -          while ((compile_block.ctypes[*ptr] & ctype_word) != 0) ptr++;
  -          if (*ptr != '>')
  -            {
  -            errorcode = ERR42;
  -            goto PCRE_ERROR_RETURN;
  -            }
  -          name_count++;
  -          if (ptr - p > max_name_size) max_name_size = (ptr - p);
  -          capturing = TRUE;   /* Named parentheses are always capturing */
  -          break;
  -          }
  -
  -        /* Handle back references and recursive calls to named subpatterns */
  -
  -        if (*ptr == '=' || *ptr == '>')
  -          {
  -          while ((compile_block.ctypes[*(++ptr)] & ctype_word) != 0);
  -          if (*ptr != ')')
  -            {
  -            errorcode = ERR42;
  -            goto PCRE_ERROR_RETURN;
  -            }
  -          break;
  -          }
  -
  -        /* Unknown character after (?P */
  -
  -        errorcode = ERR41;
  -        goto PCRE_ERROR_RETURN;
  -
           /* Lookbehinds are in Perl from version 5.005 */


           case '<':
  @@ -4564,19 +4778,17 @@


           /* 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, or (a PCRE extension) by 'R' for a recursion test. */
  +        group. PCRE extends this by allowing a name to reference a named group;
  +        unfortunately, previously 'R' was implemented for a recursion test.
  +        When this is compiled, we look for the named group 'R' first. At this
  +        point we just do a basic syntax check. */


           case '(':
  -        if (ptr[3] == 'R' && ptr[4] == ')')
  -          {
  -          ptr += 4;
  -          length += 3;
  -          }
  -        else if ((digitab[ptr[3]] & ctype_digit) != 0)
  +        if ((cd->ctypes[ptr[3]] & ctype_word) != 0)
             {
             ptr += 4;
             length += 3;
  -          while ((digitab[*ptr] & ctype_digit) != 0) ptr++;
  +          while ((cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
             if (*ptr != ')')
               {
               errorcode = ERR26;
  @@ -4615,6 +4827,11 @@
               *optset |= PCRE_CASELESS;
               continue;


  +            case 'J':
  +            *optset |= PCRE_DUPNAMES;
  +            options |= PCRE_JCHANGED;   /* Record that it changed */
  +            continue;
  +
               case 'm':
               *optset |= PCRE_MULTILINE;
               continue;
  @@ -4680,16 +4897,13 @@
               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. */
  +            branch_newextra to 2. */


               case ':':
               if (((set|unset) & PCRE_IMS) != 0)
                 {
                 length += 4;
                 branch_newextra = 2;
  -              if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
                 }
               goto END_OPTIONS;


  @@ -4769,6 +4983,12 @@
         {
         duplength = length - brastack[--brastackptr];
         branch_extra = bralenstack[brastackptr];
  +      /* This is a paranoid check to stop integer overflow later on */
  +      if (duplength > MAX_DUPLENGTH)
  +        {
  +        errorcode = ERR50;
  +        goto PCRE_ERROR_RETURN;
  +        }
         }
       else duplength = 0;


  @@ -4873,7 +5093,8 @@
     }


/* Compute the size of data block needed and get it, either from malloc or
-externally provided function. */
+externally provided function. Integer overflow should no longer be possible
+because nowadays we limit the maximum value of name_count and max_name size. */

size = length + sizeof(real_pcre) + name_count * (max_name_size + 3);
re = (real_pcre *)(pcre_malloc)(size);
@@ -4903,14 +5124,14 @@
/* The starting points of the name/number translation table and of the code are
passed around in the compile data block. */

-compile_block.names_found = 0;
-compile_block.name_entry_size = max_name_size + 3;
-compile_block.name_table = (uschar *)re + re->name_table_offset;
-codestart = compile_block.name_table + re->name_entry_size * re->name_count;
-compile_block.start_code = codestart;
-compile_block.start_pattern = (const uschar *)pattern;
-compile_block.req_varyopt = 0;
-compile_block.nopartial = FALSE;
+cd->names_found = 0;
+cd->name_entry_size = max_name_size + 3;
+cd->name_table = (uschar *)re + re->name_table_offset;
+codestart = cd->name_table + re->name_entry_size * re->name_count;
+cd->start_code = codestart;
+cd->start_pattern = (const uschar *)pattern;
+cd->req_varyopt = 0;
+cd->nopartial = FALSE;

/* Set up a starting, non-extracting bracket, then compile the expression. On
error, errorcode will be set non-zero, so we don't need to look at the result
@@ -4921,11 +5142,11 @@
*code = OP_BRA;
bracount = 0;
(void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr,
- &errorcode, FALSE, 0, &firstbyte, &reqbyte, NULL, &compile_block);
+ &errorcode, FALSE, 0, &firstbyte, &reqbyte, NULL, cd);
re->top_bracket = bracount;
-re->top_backref = compile_block.top_backref;
+re->top_backref = cd->top_backref;

-if (compile_block.nopartial) re->options |= PCRE_NOPARTIAL;
+if (cd->nopartial) re->options |= PCRE_NOPARTIAL;

/* If not reached end of pattern on success, there's an excess bracket. */

  @@ -4971,7 +5192,7 @@
   if ((options & PCRE_ANCHORED) == 0)
     {
     int temp_options = options;
  -  if (is_anchored(codestart, &temp_options, 0, compile_block.backref_map))
  +  if (is_anchored(codestart, &temp_options, 0, cd->backref_map))
       re->options |= PCRE_ANCHORED;
     else
       {
  @@ -4981,10 +5202,10 @@
         {
         int ch = firstbyte & 255;
         re->first_byte = ((firstbyte & REQ_CASELESS) != 0 &&
  -         compile_block.fcc[ch] == ch)? ch : firstbyte;
  +         cd->fcc[ch] == ch)? ch : firstbyte;
         re->options |= PCRE_FIRSTSET;
         }
  -    else if (is_startline(codestart, 0, compile_block.backref_map))
  +    else if (is_startline(codestart, 0, cd->backref_map))
         re->options |= PCRE_STARTLINE;
       }
     }
  @@ -4998,11 +5219,12 @@
     {
     int ch = reqbyte & 255;
     re->req_byte = ((reqbyte & REQ_CASELESS) != 0 &&
  -    compile_block.fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;
  +    cd->fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;
     re->options |= PCRE_REQCHSET;
     }


-/* Print out the compiled data for debugging */
+/* Print out the compiled data if debugging is enabled. This is never the
+case when building a production library. */

#ifdef DEBUG

@@ -5011,11 +5233,10 @@

   if (re->options != 0)
     {
  -  printf("%s%s%s%s%s%s%s%s%s%s\n",
  +  printf("%s%s%s%s%s%s%s%s%s\n",
       ((re->options & PCRE_NOPARTIAL) != 0)? "nopartial " : "",
       ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
       ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
  -    ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
       ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
       ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
       ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
  @@ -5027,7 +5248,8 @@
   if ((re->options & PCRE_FIRSTSET) != 0)
     {
     int ch = re->first_byte & 255;
  -  const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
  +  const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)?
  +    "" : " (caseless)";
     if (isprint(ch)) printf("First char = %c%s\n", ch, caseless);
       else printf("First char = \\x%02x%s\n", ch, caseless);
     }
  @@ -5035,12 +5257,13 @@
   if ((re->options & PCRE_REQCHSET) != 0)
     {
     int ch = re->req_byte & 255;
  -  const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
  +  const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)?
  +    "" : " (caseless)";
     if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless);
       else printf("Req char = \\x%02x%s\n", ch, caseless);
     }


-_pcre_printint(re, stdout);
+pcre_printint(re, stdout);

/* This check is done here in the debugging case so that the code that
was compiled can be seen. */

  Index: pcre_config.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_config.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_config.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_config.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_config.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_config.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


   -----------------------------------------------------------------------------
   Redistribution and use in source and binary forms, with or without
  @@ -60,7 +60,7 @@
   Returns:           0 if data returned, negative on error
   */


-EXPORT int
+PCRE_DATA_SCOPE int
pcre_config(int what, void *where)
{
switch (what)
@@ -95,6 +95,10 @@

     case PCRE_CONFIG_MATCH_LIMIT:
     *((unsigned int *)where) = MATCH_LIMIT;
  +  break;
  +
  +  case PCRE_CONFIG_MATCH_LIMIT_RECURSION:
  +  *((unsigned int *)where) = MATCH_LIMIT_RECURSION;
     break;


     case PCRE_CONFIG_STACKRECURSE:


  Index: pcre_exec.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_exec.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_exec.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_exec.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_exec.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_exec.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@
pattern matching using an NFA algorithm, trying to mimic Perl as closely as
possible. There are also some static supporting functions. */

  -
  +#define NLBLOCK md           /* The block containing newline information */
   #include "pcre_internal.h"



@@ -56,7 +56,7 @@

   typedef struct eptrblock {
     struct eptrblock *epb_prev;
  -  const uschar *epb_saved_eptr;
  +  USPTR epb_saved_eptr;
   } eptrblock;


/* Flag bits for the match() function */
@@ -130,10 +130,10 @@
*/

   static BOOL
  -match_ref(int offset, register const uschar *eptr, int length, match_data *md,
  +match_ref(int offset, register USPTR eptr, int length, match_data *md,
     unsigned long int ims)
   {
  -const uschar *p = md->start_subject + md->offset_vector[offset];
  +USPTR p = md->start_subject + md->offset_vector[offset];


   #ifdef DEBUG
   if (eptr >= md->end_subject)
  @@ -171,32 +171,50 @@
   ****************************************************************************
                      RECURSION IN THE match() FUNCTION


-The match() function is highly recursive. Some regular expressions can cause
-it to recurse thousands of times. I was writing for Unix, so I just let it
-call itself recursively. This uses the stack for saving everything that has
-to be saved for a recursive call. On Unix, the stack can be large, and this
-works fine.
-
-It turns out that on non-Unix systems there are problems with programs that
-use a lot of stack. (This despite the fact that every last chip has oodles
-of memory these days, and techniques for extending the stack have been known
-for decades.) So....
+The match() function is highly recursive, though not every recursive call
+increases the recursive depth. Nevertheless, some regular expressions can cause
+it to recurse to a great depth. I was writing for Unix, so I just let it call
+itself recursively. This uses the stack for saving everything that has to be
+saved for a recursive call. On Unix, the stack can be large, and this works
+fine.
+
+It turns out that on some non-Unix-like systems there are problems with
+programs that use a lot of stack. (This despite the fact that every last chip
+has oodles of memory these days, and techniques for extending the stack have
+been known for decades.) So....

There is a fudge, triggered by defining NO_RECURSE, which avoids recursive
calls by keeping local variables that need to be preserved in blocks of memory
-obtained from malloc instead instead of on the stack. Macros are used to
+obtained from malloc() instead instead of on the stack. Macros are used to
achieve this so that the actual code doesn't look very different to what it
always used to.
****************************************************************************
***************************************************************************/


-/* These versions of the macros use the stack, as normal */
+/* These versions of the macros use the stack, as normal. There are debugging
+versions and production versions. */

#ifndef NO_RECURSE
#define REGISTER register
-#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) rx = match(ra,rb,rc,rd,re,rf,rg)
+#ifdef DEBUG
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) \
+ { \
+ printf("match() called in line %d\n", __LINE__); \
+ rx = match(ra,rb,rc,rd,re,rf,rg,rdepth+1); \
+ printf("to line %d\n", __LINE__); \
+ }
+#define RRETURN(ra) \
+ { \
+ printf("match() returned %d from line %d ", ra, __LINE__); \
+ return ra; \
+ }
+#else
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) \
+ rx = match(ra,rb,rc,rd,re,rf,rg,rdepth+1)
#define RRETURN(ra) return ra
+#endif
+
#else


  @@ -217,6 +235,7 @@
       newframe->Xims = re;\
       newframe->Xeptrb = rf;\
       newframe->Xflags = rg;\
  +    newframe->Xrdepth = frame->Xrdepth + 1;\
       newframe->Xprevframe = frame;\
       frame = newframe;\
       DPRINTF(("restarting from line %d\n", __LINE__));\
  @@ -258,6 +277,7 @@
     long int Xims;
     eptrblock *Xeptrb;
     int Xflags;
  +  unsigned int Xrdepth;


     /* Function local variables */


@@ -280,11 +300,11 @@

   #ifdef SUPPORT_UCP
     int Xprop_type;
  +  int Xprop_value;
     int Xprop_fail_result;
     int Xprop_category;
     int Xprop_chartype;
  -  int Xprop_othercase;
  -  int Xprop_test_against;
  +  int Xprop_script;
     int *Xprop_test_variable;
   #endif


  @@ -345,26 +365,27 @@
      flags       can contain
                    match_condassert - this is an assertion condition
                    match_isgroup - this is the start of a bracketed group
  +   rdepth      the recursion depth


   Returns:       MATCH_MATCH if matched            )  these values are >= 0
                  MATCH_NOMATCH if failed to match  )
                  a negative PCRE_ERROR_xxx value if aborted by an error condition
  -                 (e.g. stopped by recursion limit)
  +                 (e.g. stopped by repeated call or recursion limit)
   */


   static int
  -match(REGISTER const uschar *eptr, REGISTER const uschar *ecode,
  +match(REGISTER USPTR eptr, REGISTER const uschar *ecode,
     int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
  -  int flags)
  +  int flags, unsigned int rdepth)
   {
   /* These variables do not need to be preserved over recursion in this function,
   so they can be ordinary variables in all cases. Mark them with "register"
   because they are used a lot in loops. */


  -register int  rrc;    /* Returns from recursive calls */
  -register int  i;      /* Used for loops not involving calls to RMATCH() */
  -register int  c;      /* Character values not kept over RMATCH() calls */
  -register BOOL utf8;   /* Local copy of UTF-8 flag for speed */
  +register int  rrc;         /* Returns from recursive calls */
  +register int  i;           /* Used for loops not involving calls to RMATCH() */
  +register unsigned int  c;  /* Character values not kept over RMATCH() calls */
  +register BOOL utf8;        /* Local copy of UTF-8 flag for speed */


/* When recursion is not being used, all "local" variables that have to be
preserved over calls to RMATCH() are part of a "frame" which is obtained from
@@ -383,6 +404,7 @@
frame->Xims = ims;
frame->Xeptrb = eptrb;
frame->Xflags = flags;
+frame->Xrdepth = rdepth;

/* This is where control jumps back to to effect "recursion" */

  @@ -396,6 +418,7 @@
   #define ims                frame->Xims
   #define eptrb              frame->Xeptrb
   #define flags              frame->Xflags
  +#define rdepth             frame->Xrdepth


/* Ditto for the local variables */

@@ -420,11 +443,11 @@

   #ifdef SUPPORT_UCP
   #define prop_type          frame->Xprop_type
  +#define prop_value         frame->Xprop_value
   #define prop_fail_result   frame->Xprop_fail_result
   #define prop_category      frame->Xprop_category
   #define prop_chartype      frame->Xprop_chartype
  -#define prop_othercase     frame->Xprop_othercase
  -#define prop_test_against  frame->Xprop_test_against
  +#define prop_script        frame->Xprop_script
   #define prop_test_variable frame->Xprop_test_variable
   #endif


@@ -454,20 +477,20 @@
#define fc c


  -#ifdef SUPPORT_UTF8                /* Many of these variables are used ony */
  -const uschar *charptr;             /* small blocks of the code. My normal  */
  -#endif                             /* style of coding would have declared  */
  -const uschar *callpat;             /* them within each of those blocks.    */
  -const uschar *data;                /* However, in order to accommodate the */
  -const uschar *next;                /* version of this code that uses an    */
  -const uschar *pp;                  /* external "stack" implemented on the  */
  -const uschar *prev;                /* heap, it is easier to declare them   */
  -const uschar *saved_eptr;          /* all here, so the declarations can    */
  -                                   /* be cut out in a block. The only      */
  -recursion_info new_recursive;      /* declarations within blocks below are */
  -                                   /* for variables that do not have to    */
  -BOOL cur_is_word;                  /* be preserved over a recursive call   */
  -BOOL condition;                    /* to RMATCH().                         */
  +#ifdef SUPPORT_UTF8                /* Many of these variables are used only  */
  +const uschar *charptr;             /* in small blocks of the code. My normal */
  +#endif                             /* style of coding would have declared    */
  +const uschar *callpat;             /* them within each of those blocks.      */
  +const uschar *data;                /* However, in order to accommodate the   */
  +const uschar *next;                /* version of this code that uses an      */
  +USPTR         pp;                  /* external "stack" implemented on the    */
  +const uschar *prev;                /* heap, it is easier to declare them all */
  +USPTR         saved_eptr;          /* here, so the declarations can be cut   */
  +                                   /* out in a block. The only declarations  */
  +recursion_info new_recursive;      /* within blocks below are for variables  */
  +                                   /* that do not have to be preserved over  */
  +BOOL cur_is_word;                  /* a recursive call to RMATCH().          */
  +BOOL condition;
   BOOL minimize;
   BOOL prev_is_word;


@@ -475,11 +498,11 @@

#ifdef SUPPORT_UCP
int prop_type;
+int prop_value;
int prop_fail_result;
int prop_category;
int prop_chartype;
-int prop_othercase;
-int prop_test_against;
+int prop_script;
int *prop_test_variable;
#endif

@@ -501,22 +524,39 @@
variables. */

#ifdef SUPPORT_UCP
+prop_value = 0;
prop_fail_result = 0;
-prop_test_against = 0;
prop_test_variable = NULL;
#endif

-/* OK, now we can get on with the real code of the function. Recursion is
-specified by the macros RMATCH and RRETURN. When NO_RECURSE is *not* defined,
-these just turn into a recursive call to match() and a "return", respectively.
-However, RMATCH isn't like a function call because it's quite a complicated
-macro. It has to be used in one particular way. This shouldn't, however, impact
-performance when true recursion is being used. */
+/* This label is used for tail recursion, which is used in a few cases even
+when NO_RECURSE is not defined, in order to reduce the amount of stack that is
+used. Thanks to Ian Taylor for noticing this possibility and sending the
+original patch. */
+
+TAIL_RECURSE:
+
+/* OK, now we can get on with the real code of the function. Recursive calls
+are specified by the macro RMATCH and RRETURN is used to return. When
+NO_RECURSE is *not* defined, these just turn into a recursive call to match()
+and a "return", respectively (possibly with some debugging if DEBUG is
+defined). However, RMATCH isn't like a function call because it's quite a
+complicated macro. It has to be used in one particular way. This shouldn't,
+however, impact performance when true recursion is being used. */
+
+/* First check that we haven't called match() too many times, or that we
+haven't exceeded the recursive call limit. */

if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT);
+if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT);

   original_ims = ims;    /* Save for resetting on ')' */
  +
  +#ifdef SUPPORT_UTF8
   utf8 = md->utf8;       /* Local copy of the flag */
  +#else
  +utf8 = FALSE;
  +#endif


   /* At the start of a bracketed group, add the current subject pointer to the
   stack of such pointers, to be re-instated at the end of the group when we hit
  @@ -616,21 +656,38 @@
       {
       case OP_BRA:     /* Non-capturing bracket: optimized */
       DPRINTF(("start bracket 0\n"));
  -    do
  +
  +    /* Loop for all the alternatives */
  +
  +    for (;;)
         {
  +      /* When we get to the final alternative within the brackets, we would
  +      return the result of a recursive call to match() whatever happened. We
  +      can reduce stack usage by turning this into a tail recursion. */
  +
  +      if (ecode[GET(ecode, 1)] != OP_ALT)
  +       {
  +       ecode += 1 + LINK_SIZE;
  +       flags = match_isgroup;
  +       DPRINTF(("bracket 0 tail recursion\n"));
  +       goto TAIL_RECURSE;
  +       }
  +
  +      /* For non-final alternatives, continue the loop for a NOMATCH result;
  +      otherwise return. */
  +
         RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
           match_isgroup);
         if (rrc != MATCH_NOMATCH) RRETURN(rrc);
         ecode += GET(ecode, 1);
         }
  -    while (*ecode == OP_ALT);
  -    DPRINTF(("bracket 0 failed\n"));
  -    RRETURN(MATCH_NOMATCH);
  +    /* Control never reaches here. */


       /* 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. */
  +    exactly what going to the ket would do. As there is only one branch to be
  +    obeyed, we can use tail recursion to avoid using another stack frame. */


       case OP_COND:
       if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */
  @@ -639,10 +696,9 @@
         condition = (offset == CREF_RECURSE * 2)?
           (md->recursive != NULL) :
           (offset < offset_top && md->offset_vector[offset] >= 0);
  -      RMATCH(rrc, eptr, ecode + (condition?
  -        (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1))),
  -        offset_top, md, ims, eptrb, match_isgroup);
  -      RRETURN(rrc);
  +      ecode += condition? (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1));
  +      flags = match_isgroup;
  +      goto TAIL_RECURSE;
         }


       /* The condition is an assertion. Call match() to evaluate it - setting
  @@ -662,9 +718,13 @@
           RRETURN(rrc);         /* Need braces because of following else */
           }
         else ecode += GET(ecode, 1);
  -      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
  -        match_isgroup);
  -      RRETURN(rrc);
  +
  +      /* We are now at the branch that is to be obeyed. As there is only one,
  +      we can use tail recursion to avoid using another stack frame. */
  +
  +      ecode += 1 + LINK_SIZE;
  +      flags = match_isgroup;
  +      goto TAIL_RECURSE;
         }
       /* Control never reaches here */


  @@ -683,7 +743,7 @@
       if (md->recursive != NULL && md->recursive->group_num == 0)
         {
         recursion_info *rec = md->recursive;
  -      DPRINTF(("Hit the end in a (?0) recursion\n"));
  +      DPRINTF(("End of pattern in a (?0) recursion\n"));
         md->recursive = rec->prevrec;
         memmove(md->offset_vector, rec->offset_save,
           rec->saved_max * sizeof(int));
  @@ -802,7 +862,7 @@
         cb.version          = 1;   /* Version 1 of the callout block */
         cb.callout_number   = ecode[1];
         cb.offset_vector    = md->offset_vector;
  -      cb.subject          = (const char *)md->start_subject;
  +      cb.subject          = (PCRE_SPTR)md->start_subject;
         cb.subject_length   = md->end_subject - md->start_subject;
         cb.start_match      = md->start_match - md->start_subject;
         cb.current_position = eptr - md->start_subject;
  @@ -884,12 +944,17 @@
               eptrb, match_isgroup);
           if (rrc == MATCH_MATCH)
             {
  +          DPRINTF(("Recursion matched\n"));
             md->recursive = new_recursive.prevrec;
             if (new_recursive.offset_save != stacksave)
               (pcre_free)(new_recursive.offset_save);
             RRETURN(MATCH_MATCH);
             }
  -        else if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +        else if (rrc != MATCH_NOMATCH)
  +          {
  +          DPRINTF(("Recursion gave error %d\n", rrc));
  +          RRETURN(rrc);
  +          }


           md->recursive = &new_recursive;
           memcpy(md->offset_vector, new_recursive.offset_save,
  @@ -914,71 +979,72 @@
       the end of a normal bracket, leaving the subject pointer. */


       case OP_ONCE:
  -      {
  -      prev = ecode;
  -      saved_eptr = eptr;
  +    prev = ecode;
  +    saved_eptr = eptr;


  -      do
  -        {
  -        RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims,
  -          eptrb, match_isgroup);
  -        if (rrc == MATCH_MATCH) break;
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        ecode += GET(ecode,1);
  -        }
  -      while (*ecode == OP_ALT);
  +    do
  +      {
  +      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims,
  +        eptrb, match_isgroup);
  +      if (rrc == MATCH_MATCH) break;
  +      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +      ecode += GET(ecode,1);
  +      }
  +    while (*ecode == OP_ALT);


  -      /* If hit the end of the group (which could be repeated), fail */
  +    /* If hit the end of the group (which could be repeated), fail */


  -      if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH);
  +    if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH);


  -      /* Continue as from after the assertion, updating the offsets high water
  -      mark, since extracts may have been taken. */
  +    /* Continue as from after the assertion, updating the offsets high water
  +    mark, since extracts may have been taken. */


  -      do ecode += GET(ecode,1); while (*ecode == OP_ALT);
  +    do ecode += GET(ecode,1); while (*ecode == OP_ALT);


  -      offset_top = md->end_offset_top;
  -      eptr = md->end_match_ptr;
  +    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. */
  +    /* 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 += 1+LINK_SIZE;
  -        break;
  -        }
  +    if (*ecode == OP_KET || eptr == saved_eptr)
  +      {
  +      ecode += 1+LINK_SIZE;
  +      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. */
  +    /* The repeating kets try the rest of the pattern or restart from the
  +    preceding bracket, in the appropriate order. The second "call" of match()
  +    uses tail recursion, to avoid using another stack frame. We need to reset
  +    any options that changed within the bracket before re-running it, so
  +    check the next opcode. */


  -      if (ecode[1+LINK_SIZE] == OP_OPT)
  -        {
  -        ims = (ims & ~PCRE_IMS) | ecode[4];
  -        DPRINTF(("ims set to %02lx at group repeat\n", ims));
  -        }
  +    if (ecode[1+LINK_SIZE] == OP_OPT)
  +      {
  +      ims = (ims & ~PCRE_IMS) | ecode[4];
  +      DPRINTF(("ims set to %02lx at group repeat\n", ims));
  +      }


  -      if (*ecode == OP_KETRMIN)
  -        {
  -        RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        }
  -      else  /* OP_KETRMAX */
  -        {
  -        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        }
  +    if (*ecode == OP_KETRMIN)
  +      {
  +      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0);
  +      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +      ecode = prev;
  +      flags = match_isgroup;
  +      goto TAIL_RECURSE;
         }
  -    RRETURN(MATCH_NOMATCH);
  +    else  /* OP_KETRMAX */
  +      {
  +      RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  +      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +      ecode += 1 + LINK_SIZE;
  +      flags = 0;
  +      goto TAIL_RECURSE;
  +      }
  +    /* Control never gets here */


       /* An alternation is the end of a branch; scan along to find the end of the
       bracketed group and go to there. */
  @@ -1022,114 +1088,114 @@
       case OP_KET:
       case OP_KETRMIN:
       case OP_KETRMAX:
  -      {
  -      prev = ecode - GET(ecode, 1);
  -      saved_eptr = eptrb->epb_saved_eptr;
  +    prev = ecode - GET(ecode, 1);
  +    saved_eptr = eptrb->epb_saved_eptr;


  -      /* Back up the stack of bracket start pointers. */
  +    /* Back up the stack of bracket start pointers. */


  -      eptrb = eptrb->epb_prev;
  +    eptrb = eptrb->epb_prev;


  -      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;
  -        RRETURN(MATCH_MATCH);
  -        }
  +    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;
  +      RRETURN(MATCH_MATCH);
  +      }


  -      /* In all other cases except a conditional group we have to check the
  -      group number back at the start and if necessary complete handling an
  -      extraction by setting the offsets and bumping the high water mark. */
  +    /* 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)
  -        {
  -        number = *prev - OP_BRA;
  +    if (*prev != OP_COND)
  +      {
  +      number = *prev - OP_BRA;


  -        /* For extended extraction brackets (large number), we have to fish out
  -        the number from a dummy opcode at the start. */
  +      /* For extended extraction brackets (large number), we have to fish out
  +      the number from a dummy opcode at the start. */


  -        if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE);
  -        offset = number << 1;
  +      if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE);
  +      offset = number << 1;


   #ifdef DEBUG
  -        printf("end bracket %d", number);
  -        printf("\n");
  +      printf("end bracket %d", number);
  +      printf("\n");
   #endif


  -        /* Test for a numbered group. This includes groups called as a result
  -        of recursion. Note that whole-pattern recursion is coded as a recurse
  -        into group 0, so it won't be picked up here. Instead, we catch it when
  -        the OP_END is reached. */
  +      /* Test for a numbered group. This includes groups called as a result
  +      of recursion. Note that whole-pattern recursion is coded as a recurse
  +      into group 0, so it won't be picked up here. Instead, we catch it when
  +      the OP_END is reached. */


  -        if (number > 0)
  +      if (number > 0)
  +        {
  +        md->capture_last = number;
  +        if (offset >= md->offset_max) md->offset_overflow = TRUE; else
             {
  -          md->capture_last = number;
  -          if (offset >= md->offset_max) md->offset_overflow = TRUE; else
  -            {
  -            md->offset_vector[offset] =
  -              md->offset_vector[md->offset_end - number];
  -            md->offset_vector[offset+1] = eptr - md->start_subject;
  -            if (offset_top <= offset) offset_top = offset + 2;
  -            }
  +          md->offset_vector[offset] =
  +            md->offset_vector[md->offset_end - number];
  +          md->offset_vector[offset+1] = eptr - md->start_subject;
  +          if (offset_top <= offset) offset_top = offset + 2;
  +          }


  -          /* Handle a recursively called group. Restore the offsets
  -          appropriately and continue from after the call. */
  +        /* Handle a recursively called group. Restore the offsets
  +        appropriately and continue from after the call. */


  -          if (md->recursive != NULL && md->recursive->group_num == number)
  -            {
  -            recursion_info *rec = md->recursive;
  -            DPRINTF(("Recursion (%d) succeeded - continuing\n", number));
  -            md->recursive = rec->prevrec;
  -            md->start_match = rec->save_start;
  -            memcpy(md->offset_vector, rec->offset_save,
  -              rec->saved_max * sizeof(int));
  -            ecode = rec->after_call;
  -            ims = original_ims;
  -            break;
  -            }
  +        if (md->recursive != NULL && md->recursive->group_num == number)
  +          {
  +          recursion_info *rec = md->recursive;
  +          DPRINTF(("Recursion (%d) succeeded - continuing\n", number));
  +          md->recursive = rec->prevrec;
  +          md->start_match = rec->save_start;
  +          memcpy(md->offset_vector, rec->offset_save,
  +            rec->saved_max * sizeof(int));
  +          ecode = rec->after_call;
  +          ims = original_ims;
  +          break;
             }
           }
  +      }


  -      /* Reset the value of the ims flags, in case they got changed during
  -      the group. */
  +    /* Reset the value of the ims flags, in case they got changed during
  +    the group. */


  -      ims = original_ims;
  -      DPRINTF(("ims reset to %02lx\n", ims));
  +    ims = original_ims;
  +    DPRINTF(("ims reset to %02lx\n", 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. */
  +    /* 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 += 1 + LINK_SIZE;
  -        break;
  -        }
  +    if (*ecode == OP_KET || eptr == saved_eptr)
  +      {
  +      ecode += 1 + LINK_SIZE;
  +      break;
  +      }


  -      /* The repeating kets try the rest of the pattern or restart from the
  -      preceding bracket, in the appropriate order. */
  +    /* The repeating kets try the rest of the pattern or restart from the
  +    preceding bracket, in the appropriate order. In the second case, we can use
  +    tail recursion to avoid using another stack frame. */


  -      if (*ecode == OP_KETRMIN)
  -        {
  -        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        }
  -      else  /* OP_KETRMAX */
  -        {
  -        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
  -        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -        }
  +    if (*ecode == OP_KETRMIN)
  +      {
  +      RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
  +      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +      ecode = prev;
  +      flags = match_isgroup;
  +      goto TAIL_RECURSE;
         }
  -
  -    RRETURN(MATCH_NOMATCH);
  +    else  /* OP_KETRMAX */
  +      {
  +      RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
  +      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +      ecode += 1 + LINK_SIZE;
  +      flags = 0;
  +      goto TAIL_RECURSE;
  +      }
  +    /* Control never gets here */


       /* Start of subject unless notbol, or after internal newline if multiline */


  @@ -1137,7 +1203,10 @@
       if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH);
       if ((ims & PCRE_MULTILINE) != 0)
         {
  -      if (eptr != md->start_subject && eptr[-1] != NEWLINE)
  +      if (eptr != md->start_subject &&
  +          (eptr == md->end_subject ||
  +           eptr < md->start_subject + md->nllen ||
  +           !IS_NEWLINE(eptr - md->nllen)))
           RRETURN(MATCH_NOMATCH);
         ecode++;
         break;
  @@ -1165,7 +1234,7 @@
       if ((ims & PCRE_MULTILINE) != 0)
         {
         if (eptr < md->end_subject)
  -        { if (*eptr != NEWLINE) RRETURN(MATCH_NOMATCH); }
  +        { if (!IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); }
         else
           { if (md->noteol) RRETURN(MATCH_NOMATCH); }
         ecode++;
  @@ -1176,14 +1245,14 @@
         if (md->noteol) RRETURN(MATCH_NOMATCH);
         if (!md->endonly)
           {
  -        if (eptr < md->end_subject - 1 ||
  -           (eptr == md->end_subject - 1 && *eptr != NEWLINE))
  +        if (eptr != md->end_subject &&
  +            (eptr != md->end_subject - md->nllen || !IS_NEWLINE(eptr)))
             RRETURN(MATCH_NOMATCH);
           ecode++;
           break;
           }
         }
  -    /* ... else fall through */
  +    /* ... else fall through for endonly */


       /* End of subject assertion (\z) */


  @@ -1195,8 +1264,9 @@
       /* End of subject or ending \n assertion (\Z) */


       case OP_EODN:
  -    if (eptr < md->end_subject - 1 ||
  -       (eptr == md->end_subject - 1 && *eptr != NEWLINE)) RRETURN(MATCH_NOMATCH);
  +    if (eptr != md->end_subject &&
  +        (eptr != md->end_subject - md->nllen || !IS_NEWLINE(eptr)))
  +      RRETURN(MATCH_NOMATCH);
       ecode++;
       break;


  @@ -1249,13 +1319,14 @@
       /* Match a single character type; inline for speed */


       case OP_ANY:
  -    if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
  -      RRETURN(MATCH_NOMATCH);
  +    if ((ims & PCRE_DOTALL) == 0)
  +      {
  +      if (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))
  +        RRETURN(MATCH_NOMATCH);
  +      }
       if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH);
  -#ifdef SUPPORT_UTF8
       if (utf8)
         while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
  -#endif
       ecode++;
       break;


  @@ -1354,23 +1425,43 @@
       if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
       GETCHARINCTEST(c, eptr);
         {
  -      int chartype, rqdtype;
  -      int othercase;
  -      int category = ucp_findchar(c, &chartype, &othercase);
  +      int chartype, script;
  +      int category = _pcre_ucp_findprop(c, &chartype, &script);


  -      rqdtype = *(++ecode);
  -      ecode++;
  -
  -      if (rqdtype >= 128)
  +      switch(ecode[1])
           {
  -        if ((rqdtype - 128 != category) == (op == OP_PROP))
  +        case PT_ANY:
  +        if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
  +        break;
  +
  +        case PT_LAMP:
  +        if ((chartype == ucp_Lu ||
  +             chartype == ucp_Ll ||
  +             chartype == ucp_Lt) == (op == OP_NOTPROP))
             RRETURN(MATCH_NOMATCH);
  -        }
  -      else
  -        {
  -        if ((rqdtype != chartype) == (op == OP_PROP))
  +         break;
  +
  +        case PT_GC:
  +        if ((ecode[2] != category) == (op == OP_PROP))
  +          RRETURN(MATCH_NOMATCH);
  +        break;
  +
  +        case PT_PC:
  +        if ((ecode[2] != chartype) == (op == OP_PROP))
  +          RRETURN(MATCH_NOMATCH);
  +        break;
  +
  +        case PT_SC:
  +        if ((ecode[2] != script) == (op == OP_PROP))
             RRETURN(MATCH_NOMATCH);
  +        break;
  +
  +        default:
  +        RRETURN(PCRE_ERROR_INTERNAL);
  +        break;
           }
  +
  +      ecode += 3;
         }
       break;


  @@ -1381,9 +1472,8 @@
       if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
       GETCHARINCTEST(c, eptr);
         {
  -      int chartype;
  -      int othercase;
  -      int category = ucp_findchar(c, &chartype, &othercase);
  +      int chartype, script;
  +      int category = _pcre_ucp_findprop(c, &chartype, &script);
         if (category == ucp_M) RRETURN(MATCH_NOMATCH);
         while (eptr < md->end_subject)
           {
  @@ -1392,7 +1482,7 @@
             {
             GETCHARLEN(c, eptr, len);
             }
  -        category = ucp_findchar(c, &chartype, &othercase);
  +        category = _pcre_ucp_findprop(c, &chartype, &script);
           if (category != ucp_M) break;
           eptr += len;
           }
  @@ -1685,8 +1775,8 @@
             while (eptr >= pp)
               {
               RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  -            eptr--;
               if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            eptr--;
               }
             }


  @@ -1843,16 +1933,12 @@
           ecode += length;


           /* If we have Unicode property support, we can use it to test the other
  -        case of the character, if there is one. The result of ucp_findchar() is
  -        < 0 if the char isn't found, and othercase is returned as zero if there
  -        isn't one. */
  +        case of the character, if there is one. */


           if (fc != dc)
             {
   #ifdef SUPPORT_UCP
  -          int chartype;
  -          int othercase;
  -          if (ucp_findchar(fc, &chartype, &othercase) < 0 || dc != othercase)
  +          if (dc != _pcre_ucp_othercase(fc))
   #endif
               RRETURN(MATCH_NOMATCH);
             }
  @@ -1920,10 +2006,9 @@


   #ifdef SUPPORT_UCP
           int othercase;
  -        int chartype;
           if ((ims & PCRE_CASELESS) != 0 &&
  -             ucp_findchar(fc, &chartype, &othercase) >= 0 &&
  -             othercase > 0)
  +            (othercase = _pcre_ucp_othercase(fc)) >= 0 &&
  +             othercase >= 0)
             oclength = _pcre_ord2utf8(othercase, occhars);
   #endif  /* SUPPORT_UCP */


  @@ -2410,16 +2495,7 @@
         {
         prop_fail_result = ctype == OP_NOTPROP;
         prop_type = *ecode++;
  -      if (prop_type >= 128)
  -        {
  -        prop_test_against = prop_type - 128;
  -        prop_test_variable = &prop_category;
  -        }
  -      else
  -        {
  -        prop_test_against = prop_type;
  -        prop_test_variable = &prop_chartype;
  -        }
  +      prop_value = *ecode++;
         }
       else prop_type = -1;
   #endif
  @@ -2436,14 +2512,68 @@
       if (min > 0)
         {
   #ifdef SUPPORT_UCP
  -      if (prop_type > 0)
  +      if (prop_type >= 0)
           {
  -        for (i = 1; i <= min; i++)
  +        switch(prop_type)
             {
  -          GETCHARINC(c, eptr);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  -          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
  -            RRETURN(MATCH_NOMATCH);
  +          case PT_ANY:
  +          if (prop_fail_result) RRETURN(MATCH_NOMATCH);
  +          for (i = 1; i <= min; i++)
  +            {
  +            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            }
  +          break;
  +
  +          case PT_LAMP:
  +          for (i = 1; i <= min; i++)
  +            {
  +            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == ucp_Lu ||
  +                 prop_chartype == ucp_Ll ||
  +                 prop_chartype == ucp_Lt) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_GC:
  +          for (i = 1; i <= min; i++)
  +            {
  +            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_category == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_PC:
  +          for (i = 1; i <= min; i++)
  +            {
  +            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_SC:
  +          for (i = 1; i <= min; i++)
  +            {
  +            if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_script == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          default:
  +          RRETURN(PCRE_ERROR_INTERNAL);
  +          break;
             }
           }


  @@ -2455,7 +2585,7 @@
           for (i = 1; i <= min; i++)
             {
             GETCHARINCTEST(c, eptr);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +          prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
             if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
             while (eptr < md->end_subject)
               {
  @@ -2464,7 +2594,7 @@
                 {
                 GETCHARLEN(c, eptr, len);
                 }
  -            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
               if (prop_category != ucp_M) break;
               eptr += len;
               }
  @@ -2483,8 +2613,11 @@
           for (i = 1; i <= min; i++)
             {
             if (eptr >= md->end_subject ||
  -             (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
  +               ((ims & PCRE_DOTALL) == 0 &&
  +                 eptr <= md->end_subject - md->nllen &&
  +                 IS_NEWLINE(eptr)))
               RRETURN(MATCH_NOMATCH);
  +          eptr++;
             while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
             }
           break;
  @@ -2569,7 +2702,11 @@
           if ((ims & PCRE_DOTALL) == 0)
             {
             for (i = 1; i <= min; i++)
  -            if (*eptr++ == NEWLINE) RRETURN(MATCH_NOMATCH);
  +            {
  +            if (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr))
  +              RRETURN(MATCH_NOMATCH);
  +            eptr++;
  +            }
             }
           else eptr += min;
           break;
  @@ -2626,17 +2763,78 @@
       if (minimize)
         {
   #ifdef SUPPORT_UCP
  -      if (prop_type > 0)
  +      if (prop_type >= 0)
           {
  -        for (fi = min;; fi++)
  +        switch(prop_type)
             {
  -          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  -          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  -          GETCHARINC(c, eptr);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  -          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
  -            RRETURN(MATCH_NOMATCH);
  +          case PT_ANY:
  +          for (fi = min;; fi++)
  +            {
  +            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  +            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            if (prop_fail_result) RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_LAMP:
  +          for (fi = min;; fi++)
  +            {
  +            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  +            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == ucp_Lu ||
  +                 prop_chartype == ucp_Ll ||
  +                 prop_chartype == ucp_Lt) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_GC:
  +          for (fi = min;; fi++)
  +            {
  +            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  +            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_category == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_PC:
  +          for (fi = min;; fi++)
  +            {
  +            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  +            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          case PT_SC:
  +          for (fi = min;; fi++)
  +            {
  +            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
  +            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  +            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +            GETCHARINC(c, eptr);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_script == prop_value) == prop_fail_result)
  +              RRETURN(MATCH_NOMATCH);
  +            }
  +          break;
  +
  +          default:
  +          RRETURN(PCRE_ERROR_INTERNAL);
  +          break;
             }
           }


  @@ -2651,7 +2849,7 @@
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
             if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
             GETCHARINCTEST(c, eptr);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +          prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
             if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
             while (eptr < md->end_subject)
               {
  @@ -2660,7 +2858,7 @@
                 {
                 GETCHARLEN(c, eptr, len);
                 }
  -            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
               if (prop_category != ucp_M) break;
               eptr += len;
               }
  @@ -2678,13 +2876,15 @@
             {
             RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +          if (fi >= max || eptr >= md->end_subject ||
  +               (ctype == OP_ANY && (ims & PCRE_DOTALL) == 0 &&
  +                eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)))
  +            RRETURN(MATCH_NOMATCH);


             GETCHARINC(c, eptr);
             switch(ctype)
               {
  -            case OP_ANY:
  -            if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
  +            case OP_ANY:        /* This is the DOTALL case */
               break;


               case OP_ANYBYTE:
  @@ -2733,12 +2933,15 @@
             {
             RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
             if (rrc != MATCH_NOMATCH) RRETURN(rrc);
  -          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
  +          if (fi >= max || eptr >= md->end_subject ||
  +               ((ims & PCRE_DOTALL) == 0 &&
  +                 eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)))
  +            RRETURN(MATCH_NOMATCH);
  +
             c = *eptr++;
             switch(ctype)
               {
  -            case OP_ANY:
  -            if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
  +            case OP_ANY:   /* This is the DOTALL case */
               break;


               case OP_ANYBYTE:
  @@ -2785,17 +2988,74 @@
         pp = eptr;  /* Remember where we started */


   #ifdef SUPPORT_UCP
  -      if (prop_type > 0)
  +      if (prop_type >= 0)
           {
  -        for (i = min; i < max; i++)
  +        switch(prop_type)
             {
  -          int len = 1;
  -          if (eptr >= md->end_subject) break;
  -          GETCHARLEN(c, eptr, len);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  -          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
  -            break;
  -          eptr+= len;
  +          case PT_ANY:
  +          for (i = min; i < max; i++)
  +            {
  +            int len = 1;
  +            if (eptr >= md->end_subject) break;
  +            GETCHARLEN(c, eptr, len);
  +            if (prop_fail_result) break;
  +            eptr+= len;
  +            }
  +          break;
  +
  +          case PT_LAMP:
  +          for (i = min; i < max; i++)
  +            {
  +            int len = 1;
  +            if (eptr >= md->end_subject) break;
  +            GETCHARLEN(c, eptr, len);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == ucp_Lu ||
  +                 prop_chartype == ucp_Ll ||
  +                 prop_chartype == ucp_Lt) == prop_fail_result)
  +              break;
  +            eptr+= len;
  +            }
  +          break;
  +
  +          case PT_GC:
  +          for (i = min; i < max; i++)
  +            {
  +            int len = 1;
  +            if (eptr >= md->end_subject) break;
  +            GETCHARLEN(c, eptr, len);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_category == prop_value) == prop_fail_result)
  +              break;
  +            eptr+= len;
  +            }
  +          break;
  +
  +          case PT_PC:
  +          for (i = min; i < max; i++)
  +            {
  +            int len = 1;
  +            if (eptr >= md->end_subject) break;
  +            GETCHARLEN(c, eptr, len);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_chartype == prop_value) == prop_fail_result)
  +              break;
  +            eptr+= len;
  +            }
  +          break;
  +
  +          case PT_SC:
  +          for (i = min; i < max; i++)
  +            {
  +            int len = 1;
  +            if (eptr >= md->end_subject) break;
  +            GETCHARLEN(c, eptr, len);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
  +            if ((prop_script == prop_value) == prop_fail_result)
  +              break;
  +            eptr+= len;
  +            }
  +          break;
             }


           /* eptr is now past the end of the maximum run */
  @@ -2818,7 +3078,7 @@
             {
             if (eptr >= md->end_subject) break;
             GETCHARINCTEST(c, eptr);
  -          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +          prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
             if (prop_category == ucp_M) break;
             while (eptr < md->end_subject)
               {
  @@ -2827,7 +3087,7 @@
                 {
                 GETCHARLEN(c, eptr, len);
                 }
  -            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
               if (prop_category != ucp_M) break;
               eptr += len;
               }
  @@ -2848,7 +3108,7 @@
                 {
                 GETCHARLEN(c, eptr, len);
                 }
  -            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
  +            prop_category = _pcre_ucp_findprop(c, &prop_chartype, &prop_script);
               if (prop_category != ucp_M) break;
               eptr--;
               }
  @@ -2867,9 +3127,9 @@
             {
             case OP_ANY:


  -          /* Special code is required for UTF8, but when the maximum is unlimited
  -          we don't need it, so we repeat the non-UTF8 code. This is probably
  -          worth it, because .* is quite a common idiom. */
  +          /* Special code is required for UTF8, but when the maximum is
  +          unlimited we don't need it, so we repeat the non-UTF8 code. This is
  +          probably worth it, because .* is quite a common idiom. */


             if (max < INT_MAX)
               {
  @@ -2877,7 +3137,9 @@
                 {
                 for (i = min; i < max; i++)
                   {
  -                if (eptr >= md->end_subject || *eptr == NEWLINE) break;
  +                if (eptr >= md->end_subject ||
  +                    (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)))
  +                  break;
                   eptr++;
                   while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
                   }
  @@ -2886,6 +3148,7 @@
                 {
                 for (i = min; i < max; i++)
                   {
  +                if (eptr >= md->end_subject) break;
                   eptr++;
                   while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
                   }
  @@ -2900,7 +3163,9 @@
                 {
                 for (i = min; i < max; i++)
                   {
  -                if (eptr >= md->end_subject || *eptr == NEWLINE) break;
  +                if (eptr >= md->end_subject ||
  +                    (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)))
  +                  break;
                   eptr++;
                   }
                 break;
  @@ -3014,7 +3279,9 @@
               {
               for (i = min; i < max; i++)
                 {
  -              if (eptr >= md->end_subject || *eptr == NEWLINE) break;
  +              if (eptr >= md->end_subject ||
  +                  (eptr <= md->end_subject - md->nllen && IS_NEWLINE(eptr)))
  +                break;
                 eptr++;
                 }
               break;
  @@ -3202,16 +3469,17 @@
                    < -1 => some kind of unexpected problem
   */


  -EXPORT int
  +PCRE_DATA_SCOPE int
   pcre_exec(const pcre *argument_re, const pcre_extra *extra_data,
  -  const char *subject, int length, int start_offset, int options, int *offsets,
  +  PCRE_SPTR subject, int length, int start_offset, int options, int *offsets,
     int offsetcount)
   {
   int rc, resetcount, ocount;
   int first_byte = -1;
   int req_byte = -1;
   int req_byte2 = -1;
  -unsigned long int ims = 0;
  +int newline;
  +unsigned long int ims;
   BOOL using_temporary_offsets = FALSE;
   BOOL anchored;
   BOOL startline;
  @@ -3219,11 +3487,12 @@
   BOOL first_byte_caseless = FALSE;
   BOOL req_byte_caseless = FALSE;
   match_data match_block;
  +match_data *md = &match_block;
   const uschar *tables;
   const uschar *start_bits = NULL;
  -const uschar *start_match = (const uschar *)subject + start_offset;
  -const uschar *end_subject;
  -const uschar *req_byte_ptr = start_match - 1;
  +USPTR start_match = (USPTR)subject + start_offset;
  +USPTR end_subject;
  +USPTR req_byte_ptr = start_match - 1;


pcre_study_data internal_study;
const pcre_study_data *study;
@@ -3243,8 +3512,9 @@
the default values. */

study = NULL;
-match_block.match_limit = MATCH_LIMIT;
-match_block.callout_data = NULL;
+md->match_limit = MATCH_LIMIT;
+md->match_limit_recursion = MATCH_LIMIT_RECURSION;
+md->callout_data = NULL;

/* The table pointer is always in native byte order. */

  @@ -3256,9 +3526,11 @@
     if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
       study = (const pcre_study_data *)extra_data->study_data;
     if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0)
  -    match_block.match_limit = extra_data->match_limit;
  +    md->match_limit = extra_data->match_limit;
  +  if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0)
  +    md->match_limit_recursion = extra_data->match_limit_recursion;
     if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
  -    match_block.callout_data = extra_data->callout_data;
  +    md->callout_data = extra_data->callout_data;
     if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables;
     }


@@ -3288,39 +3560,64 @@

/* The code starts after the real_pcre block and the capture name table. */

  -match_block.start_code = (const uschar *)external_re + re->name_table_offset +
  +md->start_code = (const uschar *)external_re + re->name_table_offset +
     re->name_count * re->name_entry_size;


  -match_block.start_subject = (const uschar *)subject;
  -match_block.start_offset = start_offset;
  -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.partial = (options & PCRE_PARTIAL) != 0;
  -match_block.hitend = FALSE;
  +md->start_subject = (USPTR)subject;
  +md->start_offset = start_offset;
  +md->end_subject = md->start_subject + length;
  +end_subject = md->end_subject;
  +
  +md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
  +md->utf8 = (re->options & PCRE_UTF8) != 0;
  +
  +md->notbol = (options & PCRE_NOTBOL) != 0;
  +md->noteol = (options & PCRE_NOTEOL) != 0;
  +md->notempty = (options & PCRE_NOTEMPTY) != 0;
  +md->partial = (options & PCRE_PARTIAL) != 0;
  +md->hitend = FALSE;
  +
  +md->recursive = NULL;                   /* No recursion at top level */


  -match_block.recursive = NULL;                   /* No recursion at top level */
  +md->lcc = tables + lcc_offset;
  +md->ctypes = tables + ctypes_offset;


  -match_block.lcc = tables + lcc_offset;
  -match_block.ctypes = tables + ctypes_offset;
  +/* Handle different types of newline. The two bits give four cases. If nothing
  +is set at run time, whatever was used at compile time applies. */
  +
  +switch ((((options & PCRE_NEWLINE_CRLF) == 0)? re->options : options) &
  +         PCRE_NEWLINE_CRLF)
  +  {
  +  default:              newline = NEWLINE; break;   /* Compile-time default */
  +  case PCRE_NEWLINE_CR: newline = '\r'; break;
  +  case PCRE_NEWLINE_LF: newline = '\n'; break;
  +  case PCRE_NEWLINE_CR+
  +       PCRE_NEWLINE_LF: newline = ('\r' << 8) | '\n'; break;
  +  }
  +
  +if (newline > 255)
  +  {
  +  md->nllen = 2;
  +  md->nl[0] = (newline >> 8) & 255;
  +  md->nl[1] = newline & 255;
  +  }
  +else
  +  {
  +  md->nllen = 1;
  +  md->nl[0] = newline;
  +  }


/* Partial matching is supported only for a restricted set of regexes at the
moment. */

  -if (match_block.partial && (re->options & PCRE_NOPARTIAL) != 0)
  +if (md->partial && (re->options & PCRE_NOPARTIAL) != 0)
     return PCRE_ERROR_BADPARTIAL;


/* Check a UTF-8 string if required. Unfortunately there's no way of passing
back the character offset. */

   #ifdef SUPPORT_UTF8
  -if (match_block.utf8 && (options & PCRE_NO_UTF8_CHECK) == 0)
  +if (md->utf8 && (options & PCRE_NO_UTF8_CHECK) == 0)
     {
     if (_pcre_valid_utf8((uschar *)subject, length) >= 0)
       return PCRE_ERROR_BADUTF8;
  @@ -3352,17 +3649,17 @@
   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;
  +  md->offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
  +  if (md->offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
     using_temporary_offsets = TRUE;
     DPRINTF(("Got memory to hold back references\n"));
     }
  -else match_block.offset_vector = offsets;
  +else md->offset_vector = offsets;


-match_block.offset_end = ocount;
-match_block.offset_max = (2*ocount)/3;
-match_block.offset_overflow = FALSE;
-match_block.capture_last = -1;
+md->offset_end = ocount;
+md->offset_max = (2*ocount)/3;
+md->offset_overflow = FALSE;
+md->capture_last = -1;

/* 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
@@ -3375,9 +3672,9 @@
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)
  +if (md->offset_vector != NULL)
     {
  -  register int *iptr = match_block.offset_vector + ocount;
  +  register int *iptr = md->offset_vector + ocount;
     register int *iend = iptr - resetcount/2 + 1;
     while (--iptr >= iend) *iptr = -1;
     }
  @@ -3394,7 +3691,7 @@
       {
       first_byte = re->first_byte & 255;
       if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE)
  -      first_byte = match_block.lcc[first_byte];
  +      first_byte = md->lcc[first_byte];
       }
     else
       if (!startline && study != NULL &&
  @@ -3417,13 +3714,13 @@


   do
     {
  -  const uschar *save_end_subject = end_subject;
  +  USPTR save_end_subject = end_subject;


     /* Reset the maximum number of extractions we might see. */


  -  if (match_block.offset_vector != NULL)
  +  if (md->offset_vector != NULL)
       {
  -    register int *iptr = match_block.offset_vector;
  +    register int *iptr = md->offset_vector;
       register int *iend = iptr + resetcount;
       while (iptr < iend) *iptr++ = -1;
       }
  @@ -3436,8 +3733,8 @@


     if (firstline)
       {
  -    const uschar *t = start_match;
  -    while (t < save_end_subject && *t != '\n') t++;
  +    USPTR t = start_match;
  +    while (t <= save_end_subject - md->nllen && !IS_NEWLINE(t)) t++;
       end_subject = t;
       }


  @@ -3447,20 +3744,22 @@
       {
       if (first_byte_caseless)
         while (start_match < end_subject &&
  -             match_block.lcc[*start_match] != first_byte)
  +             md->lcc[*start_match] != first_byte)
           start_match++;
       else
         while (start_match < end_subject && *start_match != first_byte)
           start_match++;
       }


- /* Or to just after \n for a multiline match if possible */
+ /* Or to just after a linebreak for a multiline match if possible */

     else if (startline)
       {
  -    if (start_match > match_block.start_subject + start_offset)
  +    if (start_match >= md->start_subject + md->nllen +
  +          start_offset)
         {
  -      while (start_match < end_subject && start_match[-1] != NEWLINE)
  +      while (start_match <= end_subject &&
  +             !IS_NEWLINE(start_match - md->nllen))
           start_match++;
         }
       }
  @@ -3482,7 +3781,7 @@


   #ifdef DEBUG  /* Sigh. Some compilers never learn. */
     printf(">>>> Match against: ");
  -  pchars(start_match, end_subject - start_match, TRUE, &match_block);
  +  pchars(start_match, end_subject - start_match, TRUE, md);
     printf("\n");
   #endif


@@ -3504,9 +3803,9 @@

     if (req_byte >= 0 &&
         end_subject - start_match < REQ_BYTE_MAX &&
  -      !match_block.partial)
  +      !md->partial)
       {
  -    register const uschar *p = start_match + ((first_byte >= 0)? 1 : 0);
  +    register USPTR p = start_match + ((first_byte >= 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. */
  @@ -3548,11 +3847,10 @@
     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;
- match_block.match_call_count = 0;
+ md->start_match = start_match;
+ md->match_call_count = 0;

  -  rc = match(start_match, match_block.start_code, 2, &match_block, ims, NULL,
  -    match_isgroup);
  +  rc = match(start_match, md->start_code, 2, md, ims, NULL, match_isgroup, 0);


     /* When the result is no match, if the subject's first character was a
     newline and the PCRE_FIRSTLINE option is set, break (which will return
  @@ -3563,10 +3861,13 @@


     if (rc == MATCH_NOMATCH)
       {
  -    if (firstline && *start_match == NEWLINE) break;
  +    if (firstline &&
  +        start_match <= md->end_subject - md->nllen &&
  +        IS_NEWLINE(start_match))
  +      break;
       start_match++;
   #ifdef SUPPORT_UTF8
  -    if (match_block.utf8)
  +    if (md->utf8)
         while(start_match < end_subject && (*start_match & 0xc0) == 0x80)
           start_match++;
   #endif
  @@ -3586,23 +3887,23 @@
       {
       if (offsetcount >= 4)
         {
  -      memcpy(offsets + 2, match_block.offset_vector + 2,
  +      memcpy(offsets + 2, md->offset_vector + 2,
           (offsetcount - 2) * sizeof(int));
         DPRINTF(("Copied offsets from temporary memory\n"));
         }
  -    if (match_block.end_offset_top > offsetcount)
  -      match_block.offset_overflow = TRUE;
  +    if (md->end_offset_top > offsetcount)
  +      md->offset_overflow = TRUE;


       DPRINTF(("Freeing temporary memory\n"));
  -    (pcre_free)(match_block.offset_vector);
  +    (pcre_free)(md->offset_vector);
       }


- rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
+ rc = md->offset_overflow? 0 : md->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;
  +    offsets[0] = start_match - md->start_subject;
  +    offsets[1] = md->end_match_ptr - md->start_subject;
       }


     DPRINTF((">>>> returning %d\n", rc));
  @@ -3616,10 +3917,10 @@
   if (using_temporary_offsets)
     {
     DPRINTF(("Freeing temporary memory\n"));
  -  (pcre_free)(match_block.offset_vector);
  +  (pcre_free)(md->offset_vector);
     }


  -if (match_block.partial && match_block.hitend)
  +if (md->partial && md->hitend)
     {
     DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));
     return PCRE_ERROR_PARTIAL;


  Index: pcre_fullinfo.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_fullinfo.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_fullinfo.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_fullinfo.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_fullinfo.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_fullinfo.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


   -----------------------------------------------------------------------------
   Redistribution and use in source and binary forms, with or without
  @@ -63,7 +63,7 @@
   Returns:           0 if data returned, negative on error
   */


  -EXPORT int
  +PCRE_DATA_SCOPE int
   pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what,
     void *where)
   {


  Index: pcre_get.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_get.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_get.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_get.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_get.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_get.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


   -----------------------------------------------------------------------------
   Redistribution and use in source and binary forms, with or without
  @@ -52,8 +52,8 @@
   *           Find number for named string         *
   *************************************************/


-/* This function is used by the two extraction functions below, as well
-as being generally available.
+/* This function is used by the get_first_set() function below, as well
+as being generally available. It assumes that names are unique.

   Arguments:
     code        the compiled regex
  @@ -96,6 +96,113 @@



   /*************************************************
  +*     Find (multiple) entries for named string   *
  +*************************************************/
  +
  +/* This is used by the get_first_set() function below, as well as being
  +generally available. It is used when duplicated names are permitted.
  +
  +Arguments:
  +  code        the compiled regex
  +  stringname  the name whose entries required
  +  firstptr    where to put the pointer to the first entry
  +  lastptr     where to put the pointer to the last entry
  +
  +Returns:      the length of each entry, or a negative number
  +                (PCRE_ERROR_NOSUBSTRING) if not found
  +*/
  +
  +int
  +pcre_get_stringtable_entries(const pcre *code, const char *stringname,
  +  char **firstptr, char **lastptr)
  +{
  +int rc;
  +int entrysize;
  +int top, bot;
  +uschar *nametable, *lastentry;
  +
  +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
  +  return rc;
  +if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
  +
  +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
  +  return rc;
  +if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
  +  return rc;
  +
  +lastentry = nametable + entrysize * (top - 1);
  +bot = 0;
  +while (top > bot)
  +  {
  +  int mid = (top + bot) / 2;
  +  uschar *entry = nametable + entrysize*mid;
  +  int c = strcmp(stringname, (char *)(entry + 2));
  +  if (c == 0)
  +    {
  +    uschar *first = entry;
  +    uschar *last = entry;
  +    while (first > nametable)
  +      {
  +      if (strcmp(stringname, (char *)(first - entrysize + 2)) != 0) break;
  +      first -= entrysize;
  +      }
  +    while (last < lastentry)
  +      {
  +      if (strcmp(stringname, (char *)(last + entrysize + 2)) != 0) break;
  +      last += entrysize;
  +      }
  +    *firstptr = (char *)first;
  +    *lastptr = (char *)last;
  +    return entrysize;
  +    }
  +  if (c > 0) bot = mid + 1; else top = mid;
  +  }
  +
  +return PCRE_ERROR_NOSUBSTRING;
  +}
  +
  +
  +
  +/*************************************************
  +*    Find first set of multiple named strings    *
  +*************************************************/
  +
  +/* This function allows for duplicate names in the table of named substrings.
  +It returns the number of the first one that was set in a pattern match.
  +
  +Arguments:
  +  code         the compiled regex
  +  stringname   the name of the capturing substring
  +  ovector      the vector of matched substrings
  +
  +Returns:       the number of the first that is set,
  +               or the number of the last one if none are set,
  +               or a negative number on error
  +*/
  +
  +static int
  +get_first_set(const pcre *code, const char *stringname, int *ovector)
  +{
  +const real_pcre *re = (const real_pcre *)code;
  +int entrysize;
  +char *first, *last;
  +uschar *entry;
  +if ((re->options & (PCRE_DUPNAMES | PCRE_JCHANGED)) == 0)
  +  return pcre_get_stringnumber(code, stringname);
  +entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last);
  +if (entrysize <= 0) return entrysize;
  +for (entry = (uschar *)first; entry <= (uschar *)last; entry += entrysize)
  +  {
  +  int n = (entry[0] << 8) + entry[1];
  +  if (ovector[n*2] >= 0) return n;
  +  }
  +return (first[0] << 8) + first[1];
  +}
  +
  +
  +
  +
  +/*************************************************
   *      Copy captured string to given buffer      *
   *************************************************/


@@ -144,7 +251,8 @@
*************************************************/

/* This function copies a single captured substring into a given buffer,
-identifying it by name.
+identifying it by name. If the regex permits duplicate names, the first
+substring that is set is chosen.

   Arguments:
     code           the compiled regex
  @@ -170,7 +278,7 @@
   pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector,
     int stringcount, const char *stringname, char *buffer, int size)
   {
  -int n = pcre_get_stringnumber(code, stringname);
  +int n = get_first_set(code, stringname, ovector);
   if (n <= 0) return n;
   return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size);
   }
  @@ -301,7 +409,8 @@
   *************************************************/


/* This function copies a single captured substring, identified by name, into
-new store.
+new store. If the regex permits duplicate names, the first substring that is
+set is chosen.

   Arguments:
     code           the compiled regex
  @@ -326,9 +435,10 @@
   pcre_get_named_substring(const pcre *code, const char *subject, int *ovector,
     int stringcount, const char *stringname, const char **stringptr)
   {
  -int n = pcre_get_stringnumber(code, stringname);
  +int n = get_first_set(code, stringname, ovector);
   if (n <= 0) return n;
   return pcre_get_substring(subject, ovector, stringcount, n, stringptr);
  +
   }




  Index: pcre_globals.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_globals.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_globals.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_globals.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_globals.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_globals.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without

  Index: pcre_internal.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_internal.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_internal.h    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_internal.h    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_internal.h,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_internal.h,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -9,7 +9,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -44,12 +44,14 @@
modules, but which are not relevant to the exported API. This includes some
functions whose names all begin with "_pcre_". */

+#ifndef PCRE_INTERNAL_H
+#define PCRE_INTERNAL_H

/* Define DEBUG to get debugging output on stdout. */

-/****
+#if 0
#define DEBUG
-****/
+#endif

/* 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
@@ -114,14 +116,35 @@

typedef unsigned char uschar;

-/* Include the public PCRE header */
-
-#include "pcre.h"
+/* PCRE is able to support 3 different kinds of newline (CR, LF, CRLF). The
+following macro is used to package up testing for newlines. NLBLOCK is defined
+in the various modules to indicate in which datablock the parameters exist. */
+
+#define IS_NEWLINE(p) \
+ ((p)[0] == NLBLOCK->nl[0] && \
+ (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]))
+
+/* When PCRE is compiled as a C++ library, the subject pointer can be replaced
+with a custom type. This makes it possible, for example, to allow pcre_exec()
+to process subject strings that are discontinuous by using a smart pointer
+class. It must always be possible to inspect all of the subject string in
+pcre_exec() because of the way it backtracks. Two macros are required in the
+normal case, for sign-unspecified and unsigned char pointers. The former is
+used for the external interface and appears in pcre.h, which is why its name
+must begin with PCRE_. */
+
+#ifdef CUSTOM_SUBJECT_PTR
+#define PCRE_SPTR CUSTOM_SUBJECT_PTR
+#define USPTR CUSTOM_SUBJECT_PTR
+#else
+#define PCRE_SPTR const char *
+#define USPTR const unsigned char *
+#endif

-/* Include the (copy of) the public ucp header, changing the external name into
-a private one. This does no harm, even if we aren't compiling UCP support. */
+/* Include the public PCRE header and the definitions of UCP character property
+values. */

-#define ucp_findchar _pcre_ucp_findchar
+#include "pcre.h"
#include "ucp.h"

/* When compiling for use with the Virtual Pascal compiler, these functions
@@ -147,13 +170,14 @@
#if HAVE_BCOPY
#define memmove(a, b, c) bcopy(b, a, c)
#else /* HAVE_BCOPY */
-void *
+static void *
pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n)
{
-int i;
+size_t i;
dest += n;
src += n;
for (i = 0; i < n; ++i) *(--dest) = *(--src);
+return dest;
}
#define memmove(a, b, c) pcre_memmove(a, b, c)
#endif /* not HAVE_BCOPY */
@@ -359,16 +383,17 @@

#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! */
+/* Private options flags start at the most significant end of the four bytes.
+The public options defined in pcre.h start at the least significant end. Make
+sure they don't overlap! The bits are getting a bit scarce now -- when we run
+out, there is a dummy word in the structure that could be used for the private
+bits. */

  +#define PCRE_NOPARTIAL     0x80000000  /* can't use partial with this regex */
   #define PCRE_FIRSTSET      0x40000000  /* first_byte is set */
   #define PCRE_REQCHSET      0x20000000  /* req_byte is set */
   #define PCRE_STARTLINE     0x10000000  /* start after \n for multiline */
  -#define PCRE_ICHANGED      0x08000000  /* i option changes within regex */
  -#define PCRE_NOPARTIAL     0x04000000  /* can't use partial with this regex */
  +#define PCRE_JCHANGED      0x08000000  /* j option changes within regex */


/* Options for the "extra" block produced by pcre_study(). */

  @@ -380,15 +405,17 @@
   #define PUBLIC_OPTIONS \
     (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
      PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \
  -   PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE)
  +   PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \
  +   PCRE_DUPNAMES|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF)


   #define PUBLIC_EXEC_OPTIONS \
     (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \
  -   PCRE_PARTIAL)
  +   PCRE_PARTIAL|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF)


   #define PUBLIC_DFA_EXEC_OPTIONS \
     (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \
  -   PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART)
  +   PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_CR| \
  +   PCRE_NEWLINE_LF)


#define PUBLIC_STUDY_OPTIONS 0 /* None defined */

@@ -447,6 +474,26 @@
#define ESC_tee '\t'
#endif

  +/* Codes for different types of Unicode property */
  +
  +#define PT_ANY        0    /* Any property - matches all chars */
  +#define PT_LAMP       1    /* L& - the union of Lu, Ll, Lt */
  +#define PT_GC         2    /* General characteristic (e.g. L) */
  +#define PT_PC         3    /* Particular characteristic (e.g. Lu) */
  +#define PT_SC         4    /* Script (e.g. Han) */
  +
  +/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
  +contain UTF-8 characters with values greater than 255. */
  +
  +#define XCL_NOT    0x01    /* Flag: this is a negative class */
  +#define XCL_MAP    0x02    /* Flag: a 32-byte map is present */
  +
  +#define XCL_END       0    /* Marks end of individual items */
  +#define XCL_SINGLE    1    /* Single item (one multibyte char) follows */
  +#define XCL_RANGE     2    /* A range (two multibyte chars) follows */
  +#define XCL_PROP      3    /* Unicode property (2-byte property code follows) */
  +#define XCL_NOTPROP   4    /* Unicode inverted property (ditto) */
  +
   /* 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
  @@ -462,19 +509,6 @@
          ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_X, ESC_Z, ESC_z, ESC_E,
          ESC_Q, ESC_REF };


  -/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
  -contain UTF-8 characters with values greater than 255. */
  -
  -#define XCL_NOT    0x01    /* Flag: this is a negative class */
  -#define XCL_MAP    0x02    /* Flag: a 32-byte map is present */
  -
  -#define XCL_END       0    /* Marks end of individual items */
  -#define XCL_SINGLE    1    /* Single item (one multibyte char) follows */
  -#define XCL_RANGE     2    /* A range (two multibyte chars) follows */
  -#define XCL_PROP      3    /* Unicode property (one property code) follows */
  -#define XCL_NOTPROP   4    /* Unicode inverted property (ditto) */
  -
  -
   /* 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.
  @@ -509,7 +543,7 @@
     OP_DOLL,           /* 20 End of line - varies with multiline switch */
     OP_CHAR,           /* 21 Match one character, casefully */
     OP_CHARNC,         /* 22 Match one character, caselessly */
  -  OP_NOT,            /* 23 Match anything but the following char */
  +  OP_NOT,            /* 23 Match one character, not the following one */


     OP_STAR,           /* 24 The maximizing and minimizing versions of */
     OP_MINSTAR,        /* 25 all these opcodes must come in pairs, with */
  @@ -638,7 +672,7 @@
     1,                             /* End                                    */ \
     1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \
     1, 1,                          /* Any, Anybyte                           */ \
  -  2, 2, 1,                       /* NOTPROP, PROP, EXTUNI                  */ \
  +  3, 3, 1,                       /* NOTPROP, PROP, EXTUNI                  */ \
     1, 1, 2, 1, 1,                 /* \Z, \z, Opt, ^, $                      */ \
     2,                             /* Char  - the minimum length             */ \
     2,                             /* Charnc  - the minimum length           */ \
  @@ -689,7 +723,8 @@
          ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19,
          ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29,
          ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39,
  -       ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47 };
  +       ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49,
  +       ERR50, ERR51 };


   /* The real format of the start of the pcre block; the index of names and the
   code vector run on as long as necessary after the end. We store an explicit
  @@ -753,6 +788,8 @@
     unsigned int backref_map;     /* Bitmap of low back refs */
     int  req_varyopt;             /* "After variable item" flag for reqbyte */
     BOOL nopartial;               /* Set TRUE if partial won't work */
  +  int  nllen;                   /* 1 or 2 for newline string length */
  +  uschar nl[4];                 /* Newline string */
   } compile_data;


   /* Structure for maintaining a chain of pointers to the currently incomplete
  @@ -770,18 +807,18 @@
     struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
     int group_num;                /* Number of group that was called */
     const uschar *after_call;     /* "Return value": points after the call in the expr */
  -  const uschar *save_start;     /* Old value of md->start_match */
  +  USPTR save_start;             /* Old value of md->start_match */
     int *offset_save;             /* Pointer to start of saved offsets */
     int saved_max;                /* Number of saved offsets */
   } recursion_info;


/* When compiling in a mode that doesn't use recursive calls to match(),
a structure is used to remember local variables on the heap. It is defined in
-pcre.c, close to the match() function, so that it is easy to keep it in step
-with any changes of local variable. However, the pointer to the current frame
-must be saved in some "static" place over a longjmp(). We declare the
-structure here so that we can put a pointer in the match_data structure.
-NOTE: This isn't used for a "normal" compilation of pcre. */
+pcre_exec.c, close to the match() function, so that it is easy to keep it in
+step with any changes of local variable. However, the pointer to the current
+frame must be saved in some "static" place over a longjmp(). We declare the
+structure here so that we can put a pointer in the match_data structure. NOTE:
+This isn't used for a "normal" compilation of pcre. */

struct heapframe;

@@ -789,11 +826,14 @@
doing traditional NFA matching, so that they are thread-safe. */

   typedef struct match_data {
  -  unsigned long int match_call_count; /* As it says */
  -  unsigned long int match_limit;/* As it says */
  +  unsigned long int match_call_count;      /* As it says */
  +  unsigned long int match_limit;           /* As it says */
  +  unsigned long int match_limit_recursion; /* As it says */
     int   *offset_vector;         /* Offset vector */
     int    offset_end;            /* One past the end */
     int    offset_max;            /* The maximum usable for return data */
  +  int    nllen;                 /* 1 or 2 for newline string length */
  +  uschar nl[4];                 /* Newline string */
     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 */
  @@ -805,10 +845,10 @@
     BOOL   partial;               /* PARTIAL flag */
     BOOL   hitend;                /* Hit the end of the subject at some point */
     const uschar *start_code;     /* For use when recursing */
  -  const uschar *start_subject;  /* Start of the subject string */
  -  const uschar *end_subject;    /* End of the subject string */
  -  const uschar *start_match;    /* Start of this match attempt */
  -  const uschar *end_match_ptr;  /* Subject position at end match */
  +  USPTR  start_subject;         /* Start of the subject string */
  +  USPTR  end_subject;           /* End of the subject string */
  +  USPTR  start_match;           /* Start of this match attempt */
  +  USPTR  end_match_ptr;         /* Subject position at end match */
     int    end_offset_top;        /* Highwater mark at end of match */
     int    capture_last;          /* Most recent capture number */
     int    start_offset;          /* The start offset value */
  @@ -827,6 +867,8 @@
     const uschar *tables;         /* Character tables */
     int   moptions;               /* Match options */
     int   poptions;               /* Pattern options */
  +  int    nllen;                 /* 1 or 2 for newline string length */
  +  uschar nl[4];                 /* Newline string */
     void  *callout_data;          /* To pass back to callouts */
   } dfa_match_data;


@@ -863,12 +905,13 @@
#define ctypes_offset (cbits_offset + cbit_length)
#define tables_length (ctypes_offset + 256)

-/* Layout of the UCP type table that translates property names into codes for
-ucp_findchar(). */
+/* Layout of the UCP type table that translates property names into types and
+codes. */

   typedef struct {
     const char *name;
  -  int value;
  +  pcre_uint16 type;
  +  pcre_uint16 value;
   } ucp_type_table;



@@ -897,11 +940,13 @@
sense, but are not part of the PCRE public API. */

   extern int         _pcre_ord2utf8(int, uschar *);
  -extern void        _pcre_printint(pcre *, FILE *);
   extern real_pcre * _pcre_try_flipped(const real_pcre *, real_pcre *,
                        const pcre_study_data *, pcre_study_data *);
  -extern int         _pcre_ucp_findchar(const int, int *, int *);
  +extern int         _pcre_ucp_findprop(const unsigned int, int *, int *);
  +extern int         _pcre_ucp_othercase(const int);
   extern int         _pcre_valid_utf8(const uschar *, int);
   extern BOOL        _pcre_xclass(int, const uschar *);
  +
  +#endif


/* End of pcre_internal.h */

  Index: pcre_maketables.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_maketables.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_maketables.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_maketables.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_maketables.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_maketables.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -88,29 +88,22 @@

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. Note that the
-table for "space" includes everything "isspace" gives, including VT in the
-default locale. This makes it work for the POSIX class [:space:]. */
+/* Then the character class tables. Don't try to be clever and save effort on
+exclusive ones - in some locales things may be different. Note that the table
+for "space" includes everything "isspace" gives, including VT in the default
+locale. This makes it work for the POSIX class [:space:]. Note also that it is
+possible for a character to be alnum or alpha without being lower or upper,
+such as "male and female ordinals" (\xAA and \xBA) in the fr_FR locale (at
+least under Debian Linux's locales as of 12/2005). So we must test for alnum
+specially. */

   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 (isdigit(i)) p[cbit_digit  + i/8] |= 1 << (i&7);
  +  if (isupper(i)) p[cbit_upper  + i/8] |= 1 << (i&7);
  +  if (islower(i)) p[cbit_lower  + i/8] |= 1 << (i&7);
  +  if (isalnum(i)) 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);
  @@ -139,7 +132,9 @@
     meta-character, which in this sense is any character that terminates a run
     of data characters. */


- if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; }
+ if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta;
+ *p++ = x;
+ }

return yield;
}

  Index: pcre_printint.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_printint.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_printint.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_printint.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,453 +1,2 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_printint.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_printint.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


  -/*************************************************
  -*      Perl-Compatible Regular Expressions       *
  -*************************************************/
  -
  -/* PCRE is a library of functions to support regular expressions whose syntax
  -and semantics are as close as possible to those of the Perl 5 language.
  -
  -                       Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  -
  ------------------------------------------------------------------------------
  -Redistribution and use in source and binary forms, with or without
  -modification, are permitted provided that the following conditions are met:
  -
  -    * Redistributions of source code must retain the above copyright notice,
  -      this list of conditions and the following disclaimer.
  -
  -    * Redistributions in binary form must reproduce the above copyright
  -      notice, this list of conditions and the following disclaimer in the
  -      documentation and/or other materials provided with the distribution.
  -
  -    * Neither the name of the University of Cambridge nor the names of its
  -      contributors may be used to endorse or promote products derived from
  -      this software without specific prior written permission.
  -
  -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  -POSSIBILITY OF SUCH DAMAGE.
  ------------------------------------------------------------------------------
  -*/
  -
  -
  -/* This module contains an PCRE private debugging function for printing out the
  -internal form of a compiled regular expression, along with some supporting
  -local functions. */
  -
  -
  -#include "pcre_internal.h"
  -
  -
  -static const char *OP_names[] = { OP_NAME_LIST };
  -
  -
  -/*************************************************
  -*       Print single- or multi-byte character    *
  -*************************************************/
  -
  -static int
  -print_char(FILE *f, uschar *ptr, BOOL utf8)
  -{
  -int c = *ptr;
  -
  -if (!utf8 || (c & 0xc0) != 0xc0)
  -  {
  -  if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c);
  -  return 0;
  -  }
  -else
  -  {
  -  int i;
  -  int a = _pcre_utf8_table4[c & 0x3f];  /* Number of additional bytes */
  -  int s = 6*a;
  -  c = (c & _pcre_utf8_table3[a]) << s;
  -  for (i = 1; i <= a; i++)
  -    {
  -    /* This is a check for malformed UTF-8; it should only occur if the sanity
  -    check has been turned off. Rather than swallow random bytes, just stop if
  -    we hit a bad one. Print it with \X instead of \x as an indication. */
  -
  -    if ((ptr[i] & 0xc0) != 0x80)
  -      {
  -      fprintf(f, "\\X{%x}", c);
  -      return i - 1;
  -      }
  -
  -    /* The byte is OK */
  -
  -    s -= 6;
  -    c |= (ptr[i] & 0x3f) << s;
  -    }
  -  if (c < 128) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c);
  -  return a;
  -  }
  -}
  -
  -
  -
  -/*************************************************
  -*          Find Unicode property name            *
  -*************************************************/
  -
  -static const char *
  -get_ucpname(int property)
  -{
  -#ifdef SUPPORT_UCP
  -int i;
  -for (i = _pcre_utt_size; i >= 0; i--)
  -  {
  -  if (property == _pcre_utt[i].value) break;
  -  }
  -return (i >= 0)? _pcre_utt[i].name : "??";
  -#else
  -return "??";
  -#endif
  -}
  -
  -
  -
  -/*************************************************
  -*         Print compiled regex                   *
  -*************************************************/
  -
  -/* Make this function work for a regex with integers either byte order.
  -However, we assume that what we are passed is a compiled regex. */
  -
  -EXPORT void
  -_pcre_printint(pcre *external_re, FILE *f)
  -{
  -real_pcre *re = (real_pcre *)external_re;
  -uschar *codestart, *code;
  -BOOL utf8;
  -
  -unsigned int options = re->options;
  -int offset = re->name_table_offset;
  -int count = re->name_count;
  -int size = re->name_entry_size;
  -
  -if (re->magic_number != MAGIC_NUMBER)
  -  {
  -  offset = ((offset << 8) & 0xff00) | ((offset >> 8) & 0xff);
  -  count = ((count << 8) & 0xff00) | ((count >> 8) & 0xff);
  -  size = ((size << 8) & 0xff00) | ((size >> 8) & 0xff);
  -  options = ((options << 24) & 0xff000000) |
  -            ((options <<  8) & 0x00ff0000) |
  -            ((options >>  8) & 0x0000ff00) |
  -            ((options >> 24) & 0x000000ff);
  -  }
  -
  -code = codestart = (uschar *)re + offset + count * size;
  -utf8 = (options & PCRE_UTF8) != 0;
  -
  -for(;;)
  -  {
  -  uschar *ccode;
  -  int c;
  -  int extra = 0;
  -
  -  fprintf(f, "%3d ", (int)(code - codestart));
  -
  -  if (*code >= OP_BRA)
  -    {
  -    if (*code - OP_BRA > EXTRACT_BASIC_MAX)
  -      fprintf(f, "%3d Bra extra\n", GET(code, 1));
  -    else
  -      fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA);
  -    code += _pcre_OP_lengths[OP_BRA];
  -    continue;
  -    }
  -
  -  switch(*code)
  -    {
  -    case OP_END:
  -    fprintf(f, "    %s\n", OP_names[*code]);
  -    fprintf(f, "------------------------------------------------------------------\n");
  -    return;
  -
  -    case OP_OPT:
  -    fprintf(f, " %.2x %s", code[1], OP_names[*code]);
  -    break;
  -
  -    case OP_CHAR:
  -      {
  -      fprintf(f, "    ");
  -      do
  -        {
  -        code++;
  -        code += 1 + print_char(f, code, utf8);
  -        }
  -      while (*code == OP_CHAR);
  -      fprintf(f, "\n");
  -      continue;
  -      }
  -    break;
  -
  -    case OP_CHARNC:
  -      {
  -      fprintf(f, " NC ");
  -      do
  -        {
  -        code++;
  -        code += 1 + print_char(f, code, utf8);
  -        }
  -      while (*code == OP_CHARNC);
  -      fprintf(f, "\n");
  -      continue;
  -      }
  -    break;
  -
  -    case OP_KETRMAX:
  -    case OP_KETRMIN:
  -    case OP_ALT:
  -    case OP_KET:
  -    case OP_ASSERT:
  -    case OP_ASSERT_NOT:
  -    case OP_ASSERTBACK:
  -    case OP_ASSERTBACK_NOT:
  -    case OP_ONCE:
  -    case OP_COND:
  -    case OP_REVERSE:
  -    fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
  -    break;
  -
  -    case OP_BRANUMBER:
  -    printf("%3d %s", GET2(code, 1), OP_names[*code]);
  -    break;
  -
  -    case OP_CREF:
  -    if (GET2(code, 1) == CREF_RECURSE)
  -      fprintf(f, "    Cond recurse");
  -    else
  -      fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
  -    break;
  -
  -    case OP_STAR:
  -    case OP_MINSTAR:
  -    case OP_PLUS:
  -    case OP_MINPLUS:
  -    case OP_QUERY:
  -    case OP_MINQUERY:
  -    case OP_TYPESTAR:
  -    case OP_TYPEMINSTAR:
  -    case OP_TYPEPLUS:
  -    case OP_TYPEMINPLUS:
  -    case OP_TYPEQUERY:
  -    case OP_TYPEMINQUERY:
  -    fprintf(f, "    ");
  -    if (*code >= OP_TYPESTAR)
  -      {
  -      fprintf(f, "%s", OP_names[code[1]]);
  -      if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
  -        {
  -        fprintf(f, " %s ", get_ucpname(code[2]));
  -        extra = 1;
  -        }
  -      }
  -    else extra = print_char(f, code+1, utf8);
  -    fprintf(f, "%s", OP_names[*code]);
  -    break;
  -
  -    case OP_EXACT:
  -    case OP_UPTO:
  -    case OP_MINUPTO:
  -    fprintf(f, "    ");
  -    extra = print_char(f, code+3, utf8);
  -    fprintf(f, "{");
  -    if (*code != OP_EXACT) fprintf(f, ",");
  -    fprintf(f, "%d}", GET2(code,1));
  -    if (*code == OP_MINUPTO) fprintf(f, "?");
  -    break;
  -
  -    case OP_TYPEEXACT:
  -    case OP_TYPEUPTO:
  -    case OP_TYPEMINUPTO:
  -    fprintf(f, "    %s", OP_names[code[3]]);
  -    if (code[3] == OP_PROP || code[3] == OP_NOTPROP)
  -      {
  -      fprintf(f, " %s ", get_ucpname(code[4]));
  -      extra = 1;
  -      }
  -    fprintf(f, "{");
  -    if (*code != OP_TYPEEXACT) fprintf(f, "0,");
  -    fprintf(f, "%d}", GET2(code,1));
  -    if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
  -    break;
  -
  -    case OP_NOT:
  -    if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
  -      else fprintf(f, "    [^\\x%02x]", c);
  -    break;
  -
  -    case OP_NOTSTAR:
  -    case OP_NOTMINSTAR:
  -    case OP_NOTPLUS:
  -    case OP_NOTMINPLUS:
  -    case OP_NOTQUERY:
  -    case OP_NOTMINQUERY:
  -    if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
  -      else fprintf(f, "    [^\\x%02x]", c);
  -    fprintf(f, "%s", OP_names[*code]);
  -    break;
  -
  -    case OP_NOTEXACT:
  -    case OP_NOTUPTO:
  -    case OP_NOTMINUPTO:
  -    if (isprint(c = code[3])) fprintf(f, "    [^%c]{", c);
  -      else fprintf(f, "    [^\\x%02x]{", c);
  -    if (*code != OP_NOTEXACT) fprintf(f, "0,");
  -    fprintf(f, "%d}", GET2(code,1));
  -    if (*code == OP_NOTMINUPTO) fprintf(f, "?");
  -    break;
  -
  -    case OP_RECURSE:
  -    fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
  -    break;
  -
  -    case OP_REF:
  -    fprintf(f, "    \\%d", GET2(code,1));
  -    ccode = code + _pcre_OP_lengths[*code];
  -    goto CLASS_REF_REPEAT;
  -
  -    case OP_CALLOUT:
  -    fprintf(f, "    %s %d %d %d", OP_names[*code], code[1], GET(code,2),
  -      GET(code, 2 + LINK_SIZE));
  -    break;
  -
  -    case OP_PROP:
  -    case OP_NOTPROP:
  -    fprintf(f, "    %s %s", OP_names[*code], get_ucpname(code[1]));
  -    break;
  -
  -    /* OP_XCLASS can only occur in UTF-8 mode. However, there's no harm in
  -    having this code always here, and it makes it less messy without all those
  -    #ifdefs. */
  -
  -    case OP_CLASS:
  -    case OP_NCLASS:
  -    case OP_XCLASS:
  -      {
  -      int i, min, max;
  -      BOOL printmap;
  -
  -      fprintf(f, "    [");
  -
  -      if (*code == OP_XCLASS)
  -        {
  -        extra = GET(code, 1);
  -        ccode = code + LINK_SIZE + 1;
  -        printmap = (*ccode & XCL_MAP) != 0;
  -        if ((*ccode++ & XCL_NOT) != 0) fprintf(f, "^");
  -        }
  -      else
  -        {
  -        printmap = TRUE;
  -        ccode = code + 1;
  -        }
  -
  -      /* Print a bit map */
  -
  -      if (printmap)
  -        {
  -        for (i = 0; i < 256; i++)
  -          {
  -          if ((ccode[i/8] & (1 << (i&7))) != 0)
  -            {
  -            int j;
  -            for (j = i+1; j < 256; j++)
  -              if ((ccode[j/8] & (1 << (j&7))) == 0) break;
  -            if (i == '-' || i == ']') fprintf(f, "\\");
  -            if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i);
  -            if (--j > i)
  -              {
  -              if (j != i + 1) fprintf(f, "-");
  -              if (j == '-' || j == ']') fprintf(f, "\\");
  -              if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j);
  -              }
  -            i = j;
  -            }
  -          }
  -        ccode += 32;
  -        }
  -
  -      /* For an XCLASS there is always some additional data */
  -
  -      if (*code == OP_XCLASS)
  -        {
  -        int ch;
  -        while ((ch = *ccode++) != XCL_END)
  -          {
  -          if (ch == XCL_PROP)
  -            {
  -            fprintf(f, "\\p{%s}", get_ucpname(*ccode++));
  -            }
  -          else if (ch == XCL_NOTPROP)
  -            {
  -            fprintf(f, "\\P{%s}", get_ucpname(*ccode++));
  -            }
  -          else
  -            {
  -            ccode += 1 + print_char(f, ccode, TRUE);
  -            if (ch == XCL_RANGE)
  -              {
  -              fprintf(f, "-");
  -              ccode += 1 + print_char(f, ccode, TRUE);
  -              }
  -            }
  -          }
  -        }
  -
  -      /* Indicate a non-UTF8 class which was created by negation */
  -
  -      fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
  -
  -      /* Handle repeats after a class or a back reference */
  -
  -      CLASS_REF_REPEAT:
  -      switch(*ccode)
  -        {
  -        case OP_CRSTAR:
  -        case OP_CRMINSTAR:
  -        case OP_CRPLUS:
  -        case OP_CRMINPLUS:
  -        case OP_CRQUERY:
  -        case OP_CRMINQUERY:
  -        fprintf(f, "%s", OP_names[*ccode]);
  -        extra += _pcre_OP_lengths[*ccode];
  -        break;
  -
  -        case OP_CRRANGE:
  -        case OP_CRMINRANGE:
  -        min = GET2(ccode,1);
  -        max = GET2(ccode,3);
  -        if (max == 0) fprintf(f, "{%d,}", min);
  -        else fprintf(f, "{%d,%d}", min, max);
  -        if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
  -        extra += _pcre_OP_lengths[*ccode];
  -        break;
  -        }
  -      }
  -    break;
  -
  -    /* Anything else is just an item with no data*/
  -
  -    default:
  -    fprintf(f, "    %s", OP_names[*code]);
  -    break;
  -    }
  -
  -  code += _pcre_OP_lengths[*code] + extra;
  -  fprintf(f, "\n");
  -  }
  -}
  -
  -/* End of pcre_printint.c */


  Index: pcre_study.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_study.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_study.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_study.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_study.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_study.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -97,6 +97,13 @@
{
register int c;

+#if 0
+/* ========================================================================= */
+/* The following comment and code was inserted in January 1999. In May 2006,
+when it was observed to cause compiler warnings about unused values, I took it
+out again. If anybody is still using OS/2, they will have to put it back
+manually. */
+
/* 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
@@ -104,6 +111,8 @@
the pcre module can use all the optimization it can get). */

volatile int dummy;
+/* ========================================================================= */
+#endif

   do
     {
  @@ -161,7 +170,11 @@
         case OP_BRAMINZERO:
         if (!set_start_bits(++tcode, start_bits, caseless, utf8, cd))
           return FALSE;
  +/* =========================================================================
  +      See the comment at the head of this function concerning the next line,
  +      which was an old fudge for the benefit of OS/2.
         dummy = 1;
  +  ========================================================================= */
         do tcode += GET(tcode,1); while (*tcode == OP_ALT);
         tcode += 1+LINK_SIZE;
         break;
  @@ -217,15 +230,29 @@
         try_next = FALSE;
         break;


  +      /* The cbit_space table has vertical tab as whitespace; we have to
  +      discard it. */
  +
         case OP_NOT_WHITESPACE:
         for (c = 0; c < 32; c++)
  -        start_bits[c] |= ~cd->cbits[c+cbit_space];
  +        {
  +        int d = cd->cbits[c+cbit_space];
  +        if (c == 1) d &= ~0x08;
  +        start_bits[c] |= ~d;
  +        }
         try_next = FALSE;
         break;


  +      /* The cbit_space table has vertical tab as whitespace; we have to
  +      discard it. */
  +
         case OP_WHITESPACE:
         for (c = 0; c < 32; c++)
  -        start_bits[c] |= cd->cbits[c+cbit_space];
  +        {
  +        int d = cd->cbits[c+cbit_space];
  +        if (c == 1) d &= ~0x08;
  +        start_bits[c] |= d;
  +        }
         try_next = FALSE;
         break;


  @@ -279,14 +306,28 @@
             start_bits[c] |= cd->cbits[c+cbit_digit];
           break;


  +        /* The cbit_space table has vertical tab as whitespace; we have to
  +        discard it. */
  +
           case OP_NOT_WHITESPACE:
           for (c = 0; c < 32; c++)
  -          start_bits[c] |= ~cd->cbits[c+cbit_space];
  +          {
  +          int d = cd->cbits[c+cbit_space];
  +          if (c == 1) d &= ~0x08;
  +          start_bits[c] |= ~d;
  +          }
           break;


  +        /* The cbit_space table has vertical tab as whitespace; we have to
  +        discard it. */
  +
           case OP_WHITESPACE:
           for (c = 0; c < 32; c++)
  -          start_bits[c] |= cd->cbits[c+cbit_space];
  +          {
  +          int d = cd->cbits[c+cbit_space];
  +          if (c == 1) d &= ~0x08;
  +          start_bits[c] |= d;
  +          }
           break;


           case OP_NOT_WORDCHAR:
  @@ -403,17 +444,16 @@
               NULL on error or if no optimization possible
   */


-EXPORT pcre_extra *
+PCRE_DATA_SCOPE pcre_extra *
pcre_study(const pcre *external_re, int options, const char **errorptr)
{
uschar start_bits[32];
pcre_extra *extra;
pcre_study_data *study;
const uschar *tables;
-const real_pcre *re = (const real_pcre *)external_re;
-uschar *code = (uschar *)re + re->name_table_offset +
- (re->name_count * re->name_entry_size);
+uschar *code;
compile_data compile_block;
+const real_pcre *re = (const real_pcre *)external_re;

*errorptr = NULL;

  @@ -428,6 +468,9 @@
     *errorptr = "unknown or incorrect option bit(s) set";
     return NULL;
     }
  +
  +code = (uschar *)re + re->name_table_offset +
  +  (re->name_count * re->name_entry_size);


/* For an anchored pattern, or an unanchored pattern that has a first char, or
a multiline pattern that matches only at "line starts", no further processing

  Index: pcre_tables.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_tables.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_tables.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_tables.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_tables.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_tables.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -41,14 +41,16 @@


/* This module contains some fixed tables that are used by more than one of the
-PCRE code modules. */
+PCRE code modules. The tables are also #included by the pcretest program, which
+uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name
+clashes with the library. */


#include "pcre_internal.h"


/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
-the definition is next to the definition of the opcodes in internal.h. */
+the definition is next to the definition of the opcodes in pcre_internal.h. */

const uschar _pcre_OP_lengths[] = { OP_LENGTHS };

  @@ -82,48 +84,110 @@
     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
     3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };


-/* This table translates Unicode property names into code values for the
-ucp_findchar() function. It is used by pcretest as well as by the library
-functions. */
+/* This table translates Unicode property names into type and code values. It
+is searched by binary chop, so must be in collating sequence of name. */

   const ucp_type_table _pcre_utt[] = {
  -  { "C",  128 + ucp_C },
  -  { "Cc", ucp_Cc },
  -  { "Cf", ucp_Cf },
  -  { "Cn", ucp_Cn },
  -  { "Co", ucp_Co },
  -  { "Cs", ucp_Cs },
  -  { "L",  128 + ucp_L },
  -  { "Ll", ucp_Ll },
  -  { "Lm", ucp_Lm },
  -  { "Lo", ucp_Lo },
  -  { "Lt", ucp_Lt },
  -  { "Lu", ucp_Lu },
  -  { "M",  128 + ucp_M },
  -  { "Mc", ucp_Mc },
  -  { "Me", ucp_Me },
  -  { "Mn", ucp_Mn },
  -  { "N",  128 + ucp_N },
  -  { "Nd", ucp_Nd },
  -  { "Nl", ucp_Nl },
  -  { "No", ucp_No },
  -  { "P",  128 + ucp_P },
  -  { "Pc", ucp_Pc },
  -  { "Pd", ucp_Pd },
  -  { "Pe", ucp_Pe },
  -  { "Pf", ucp_Pf },
  -  { "Pi", ucp_Pi },
  -  { "Po", ucp_Po },
  -  { "Ps", ucp_Ps },
  -  { "S",  128 + ucp_S },
  -  { "Sc", ucp_Sc },
  -  { "Sk", ucp_Sk },
  -  { "Sm", ucp_Sm },
  -  { "So", ucp_So },
  -  { "Z",  128 + ucp_Z },
  -  { "Zl", ucp_Zl },
  -  { "Zp", ucp_Zp },
  -  { "Zs", ucp_Zs }
  +  { "Any",                 PT_ANY,  0 },
  +  { "Arabic",              PT_SC,   ucp_Arabic },
  +  { "Armenian",            PT_SC,   ucp_Armenian },
  +  { "Bengali",             PT_SC,   ucp_Bengali },
  +  { "Bopomofo",            PT_SC,   ucp_Bopomofo },
  +  { "Braille",             PT_SC,   ucp_Braille },
  +  { "Buginese",            PT_SC,   ucp_Buginese },
  +  { "Buhid",               PT_SC,   ucp_Buhid },
  +  { "C",                   PT_GC,   ucp_C },
  +  { "Canadian_Aboriginal", PT_SC,   ucp_Canadian_Aboriginal },
  +  { "Cc",                  PT_PC,   ucp_Cc },
  +  { "Cf",                  PT_PC,   ucp_Cf },
  +  { "Cherokee",            PT_SC,   ucp_Cherokee },
  +  { "Cn",                  PT_PC,   ucp_Cn },
  +  { "Co",                  PT_PC,   ucp_Co },
  +  { "Common",              PT_SC,   ucp_Common },
  +  { "Coptic",              PT_SC,   ucp_Coptic },
  +  { "Cs",                  PT_PC,   ucp_Cs },
  +  { "Cypriot",             PT_SC,   ucp_Cypriot },
  +  { "Cyrillic",            PT_SC,   ucp_Cyrillic },
  +  { "Deseret",             PT_SC,   ucp_Deseret },
  +  { "Devanagari",          PT_SC,   ucp_Devanagari },
  +  { "Ethiopic",            PT_SC,   ucp_Ethiopic },
  +  { "Georgian",            PT_SC,   ucp_Georgian },
  +  { "Glagolitic",          PT_SC,   ucp_Glagolitic },
  +  { "Gothic",              PT_SC,   ucp_Gothic },
  +  { "Greek",               PT_SC,   ucp_Greek },
  +  { "Gujarati",            PT_SC,   ucp_Gujarati },
  +  { "Gurmukhi",            PT_SC,   ucp_Gurmukhi },
  +  { "Han",                 PT_SC,   ucp_Han },
  +  { "Hangul",              PT_SC,   ucp_Hangul },
  +  { "Hanunoo",             PT_SC,   ucp_Hanunoo },
  +  { "Hebrew",              PT_SC,   ucp_Hebrew },
  +  { "Hiragana",            PT_SC,   ucp_Hiragana },
  +  { "Inherited",           PT_SC,   ucp_Inherited },
  +  { "Kannada",             PT_SC,   ucp_Kannada },
  +  { "Katakana",            PT_SC,   ucp_Katakana },
  +  { "Kharoshthi",          PT_SC,   ucp_Kharoshthi },
  +  { "Khmer",               PT_SC,   ucp_Khmer },
  +  { "L",                   PT_GC,   ucp_L },
  +  { "L&",                  PT_LAMP, 0 },
  +  { "Lao",                 PT_SC,   ucp_Lao },
  +  { "Latin",               PT_SC,   ucp_Latin },
  +  { "Limbu",               PT_SC,   ucp_Limbu },
  +  { "Linear_B",            PT_SC,   ucp_Linear_B },
  +  { "Ll",                  PT_PC,   ucp_Ll },
  +  { "Lm",                  PT_PC,   ucp_Lm },
  +  { "Lo",                  PT_PC,   ucp_Lo },
  +  { "Lt",                  PT_PC,   ucp_Lt },
  +  { "Lu",                  PT_PC,   ucp_Lu },
  +  { "M",                   PT_GC,   ucp_M },
  +  { "Malayalam",           PT_SC,   ucp_Malayalam },
  +  { "Mc",                  PT_PC,   ucp_Mc },
  +  { "Me",                  PT_PC,   ucp_Me },
  +  { "Mn",                  PT_PC,   ucp_Mn },
  +  { "Mongolian",           PT_SC,   ucp_Mongolian },
  +  { "Myanmar",             PT_SC,   ucp_Myanmar },
  +  { "N",                   PT_GC,   ucp_N },
  +  { "Nd",                  PT_PC,   ucp_Nd },
  +  { "New_Tai_Lue",         PT_SC,   ucp_New_Tai_Lue },
  +  { "Nl",                  PT_PC,   ucp_Nl },
  +  { "No",                  PT_PC,   ucp_No },
  +  { "Ogham",               PT_SC,   ucp_Ogham },
  +  { "Old_Italic",          PT_SC,   ucp_Old_Italic },
  +  { "Old_Persian",         PT_SC,   ucp_Old_Persian },
  +  { "Oriya",               PT_SC,   ucp_Oriya },
  +  { "Osmanya",             PT_SC,   ucp_Osmanya },
  +  { "P",                   PT_GC,   ucp_P },
  +  { "Pc",                  PT_PC,   ucp_Pc },
  +  { "Pd",                  PT_PC,   ucp_Pd },
  +  { "Pe",                  PT_PC,   ucp_Pe },
  +  { "Pf",                  PT_PC,   ucp_Pf },
  +  { "Pi",                  PT_PC,   ucp_Pi },
  +  { "Po",                  PT_PC,   ucp_Po },
  +  { "Ps",                  PT_PC,   ucp_Ps },
  +  { "Runic",               PT_SC,   ucp_Runic },
  +  { "S",                   PT_GC,   ucp_S },
  +  { "Sc",                  PT_PC,   ucp_Sc },
  +  { "Shavian",             PT_SC,   ucp_Shavian },
  +  { "Sinhala",             PT_SC,   ucp_Sinhala },
  +  { "Sk",                  PT_PC,   ucp_Sk },
  +  { "Sm",                  PT_PC,   ucp_Sm },
  +  { "So",                  PT_PC,   ucp_So },
  +  { "Syloti_Nagri",        PT_SC,   ucp_Syloti_Nagri },
  +  { "Syriac",              PT_SC,   ucp_Syriac },
  +  { "Tagalog",             PT_SC,   ucp_Tagalog },
  +  { "Tagbanwa",            PT_SC,   ucp_Tagbanwa },
  +  { "Tai_Le",              PT_SC,   ucp_Tai_Le },
  +  { "Tamil",               PT_SC,   ucp_Tamil },
  +  { "Telugu",              PT_SC,   ucp_Telugu },
  +  { "Thaana",              PT_SC,   ucp_Thaana },
  +  { "Thai",                PT_SC,   ucp_Thai },
  +  { "Tibetan",             PT_SC,   ucp_Tibetan },
  +  { "Tifinagh",            PT_SC,   ucp_Tifinagh },
  +  { "Ugaritic",            PT_SC,   ucp_Ugaritic },
  +  { "Yi",                  PT_SC,   ucp_Yi },
  +  { "Z",                   PT_GC,   ucp_Z },
  +  { "Zl",                  PT_PC,   ucp_Zl },
  +  { "Zp",                  PT_PC,   ucp_Zp },
  +  { "Zs",                  PT_PC,   ucp_Zs }
   };


const int _pcre_utt_size = sizeof(_pcre_utt)/sizeof(ucp_type_table);

  Index: pcre_try_flipped.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_try_flipped.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_try_flipped.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_try_flipped.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_try_flipped.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_try_flipped.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


   -----------------------------------------------------------------------------
   Redistribution and use in source and binary forms, with or without
  @@ -64,8 +64,8 @@
   Returns:       the flipped value
   */


  -static long int
  -byteflip(long int value, int n)
  +static unsigned long int
  +byteflip(unsigned long int value, int n)
   {
   if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
   return ((value & 0x000000ff) << 24) |
  @@ -96,7 +96,7 @@
                      NULL if it is not
   */


  -EXPORT real_pcre *
  +real_pcre *
   _pcre_try_flipped(const real_pcre *re, real_pcre *internal_re,
     const pcre_study_data *study, pcre_study_data *internal_study)
   {


  Index: pcre_version.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcre_version.c,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- pcre_version.c    8 Aug 2005 10:22:14 -0000    1.2
  +++ pcre_version.c    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcre_version.c,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcre_version.c,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *      Perl-Compatible Regular Expressions       *
  @@ -8,7 +8,7 @@
   and semantics are as close as possible to those of the Perl 5 language.


                          Written by Philip Hazel
  -           Copyright (c) 1997-2005 University of Cambridge
  +           Copyright (c) 1997-2006 University of Cambridge


-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -54,10 +54,13 @@
#define STRING(a) # a
#define XSTRING(s) STRING(s)

  -EXPORT const char *
  +PCRE_DATA_SCOPE const char *
   pcre_version(void)
   {
  -return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
  +return XSTRING(PCRE_MAJOR)
  +       "." XSTRING(PCRE_MINOR)
  +           XSTRING(PCRE_PRERELEASE)
  +       " " XSTRING(PCRE_DATE);
   }


/* End of pcre_version.c */

  Index: pcretest.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/pcretest.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- pcretest.c    8 Aug 2005 10:22:14 -0000    1.3
  +++ pcretest.c    7 Nov 2006 16:50:36 -0000    1.4
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/pcre/pcretest.c,v 1.3 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/pcretest.c,v 1.4 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
   *             PCRE testing program               *
  @@ -46,15 +46,40 @@
   #include <locale.h>
   #include <errno.h>


  +#ifndef _WIN32
  +#include <sys/resource.h>
  +#endif
  +
   #define PCRE_SPY        /* For Win32 build, import data, not export */


-/* We need the internal info for displaying the results of pcre_study() and
-other internal data; pcretest also uses some of the fixed tables, and generally
-has "inside information" compared to a program that strictly follows the PCRE
-API. */
+/* We include pcre_internal.h because we need the internal info for displaying
+the results of pcre_study() and we also need to know about the internal
+macros, structures, and other internal data values; pcretest has "inside
+information" compared to a program that strictly follows the PCRE API. */

#include "pcre_internal.h"

  +/* We need access to the data tables that PCRE uses. So as not to have to keep
  +two copies, we include the source file here, changing the names of the external
  +symbols to prevent clashes. */
  +
  +#define _pcre_utf8_table1      utf8_table1
  +#define _pcre_utf8_table1_size utf8_table1_size
  +#define _pcre_utf8_table2      utf8_table2
  +#define _pcre_utf8_table3      utf8_table3
  +#define _pcre_utf8_table4      utf8_table4
  +#define _pcre_utt              utt
  +#define _pcre_utt_size         utt_size
  +#define _pcre_OP_lengths       OP_lengths
  +
  +#include "pcre_tables.c"
  +
  +/* We also need the pcre_printint() function for printing out compiled
  +patterns. This function is in a separate file so that it can be included in
  +pcre_compile.c when that module is compiled with debugging enabled. */
  +
  +#include "pcre_printint.src"
  +


/* It is possible to compile this test program without including support for
testing the POSIX interface, though this is not available via the standard
@@ -70,6 +95,8 @@
function (define NOINFOCHECK). */


+/* Other parameters */
+
#ifndef CLOCKS_PER_SEC
#ifdef CLK_TCK
#define CLOCKS_PER_SEC CLK_TCK
@@ -80,10 +107,7 @@

#define LOOPREPEAT 500000

-#define BUFFER_SIZE 30000
-#define PBUFFER_SIZE BUFFER_SIZE
-#define DBUFFER_SIZE BUFFER_SIZE
-
+/* Static variables */

static FILE *outfile;
static int log_store = 0;
@@ -96,11 +120,96 @@
static int use_utf8;
static size_t gotten_store;

+/* The buffers grow automatically if very long input lines are encountered. */
+
+static int buffer_size = 50000;
+static uschar *buffer = NULL;
+static uschar *dbuffer = NULL;
static uschar *pbuffer = NULL;



   /*************************************************
  +*        Read or extend an input line            *
  +*************************************************/
  +
  +/* Input lines are read into buffer, but both patterns and data lines can be
  +continued over multiple input lines. In addition, if the buffer fills up, we
  +want to automatically expand it so as to be able to handle extremely large
  +lines that are needed for certain stress tests. When the input buffer is
  +expanded, the other two buffers must also be expanded likewise, and the
  +contents of pbuffer, which are a copy of the input for callouts, must be
  +preserved (for when expansion happens for a data line). This is not the most
  +optimal way of handling this, but hey, this is just a test program!
  +
  +Arguments:
  +  f            the file to read
  +  start        where in buffer to start (this *must* be within buffer)
  +
  +Returns:       pointer to the start of new data
  +               could be a copy of start, or could be moved
  +               NULL if no data read and EOF reached
  +*/
  +
  +static uschar *
  +extend_inputline(FILE *f, uschar *start)
  +{
  +uschar *here = start;
  +
  +for (;;)
  +  {
  +  int rlen = buffer_size - (here - buffer);
  +  if (rlen > 1000)
  +    {
  +    int dlen;
  +    if (fgets((char *)here, rlen,  f) == NULL)
  +      return (here == start)? NULL : start;
  +    dlen = (int)strlen((char *)here);
  +    if (dlen > 0 && here[dlen - 1] == '\n') return start;
  +    here += dlen;
  +    }
  +
  +  else
  +    {
  +    int new_buffer_size = 2*buffer_size;
  +    uschar *new_buffer = (unsigned char *)malloc(new_buffer_size);
  +    uschar *new_dbuffer = (unsigned char *)malloc(new_buffer_size);
  +    uschar *new_pbuffer = (unsigned char *)malloc(new_buffer_size);
  +
  +    if (new_buffer == NULL || new_dbuffer == NULL || new_pbuffer == NULL)
  +      {
  +      fprintf(stderr, "pcretest: malloc(%d) failed\n", new_buffer_size);
  +      exit(1);
  +      }
  +
  +    memcpy(new_buffer, buffer, buffer_size);
  +    memcpy(new_pbuffer, pbuffer, buffer_size);
  +
  +    buffer_size = new_buffer_size;
  +
  +    start = new_buffer + (start - buffer);
  +    here = new_buffer + (here - buffer);
  +
  +    free(buffer);
  +    free(dbuffer);
  +    free(pbuffer);
  +
  +    buffer = new_buffer;
  +    dbuffer = new_dbuffer;
  +    pbuffer = new_pbuffer;
  +    }
  +  }
  +
  +return NULL;  /* Control never gets here */
  +}
  +
  +
  +
  +
  +
  +
  +
  +/*************************************************
   *          Read number from string               *
   *************************************************/


@@ -136,19 +245,19 @@
and returns the value of the character.

   Argument:
  -  buffer   a pointer to the byte vector
  -  vptr     a pointer to an int to receive the value
  +  utf8bytes   a pointer to the byte vector
  +  vptr        a pointer to an int to receive the value


  -Returns:   >  0 => the number of bytes consumed
  -           -6 to 0 => malformed UTF-8 character at offset = (-return)
  +Returns:      >  0 => the number of bytes consumed
  +              -6 to 0 => malformed UTF-8 character at offset = (-return)
   */


#if !defined NOUTF8

static int
-utf82ord(unsigned char *buffer, int *vptr)
+utf82ord(unsigned char *utf8bytes, int *vptr)
{
-int c = *buffer++;
+int c = *utf8bytes++;
int d = c;
int i, j, s;

@@ -164,11 +273,11 @@
/* i now has a value in the range 1-5 */

s = 6*i;
-d = (c & _pcre_utf8_table3[i]) << s;
+d = (c & utf8_table3[i]) << s;

   for (j = 0; j < i; j++)
     {
  -  c = *buffer++;
  +  c = *utf8bytes++;
     if ((c & 0xc0) != 0x80) return -(j+1);
     s -= 6;
     d |= (c & 0x3f) << s;
  @@ -176,8 +285,8 @@


/* Check that encoding was the correct unique one */

-for (j = 0; j < _pcre_utf8_table1_size; j++)
- if (d <= _pcre_utf8_table1[j]) break;
+for (j = 0; j < utf8_table1_size; j++)
+ if (d <= utf8_table1[j]) break;
if (j != i) return -(i+1);

/* Valid value */
@@ -191,6 +300,42 @@


   /*************************************************
  +*       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
  +  utf8bytes  pointer to buffer for result - at least 6 bytes long
  +
  +Returns:     number of characters placed in the buffer
  +*/
  +
  +#if !defined NOUTF8
  +
  +static int
  +ord2utf8(int cvalue, uschar *utf8bytes)
  +{
  +register int i, j;
  +for (i = 0; i < utf8_table1_size; i++)
  +  if (cvalue <= utf8_table1[i]) break;
  +utf8bytes += i;
  +for (j = i; j > 0; j--)
  + {
  + *utf8bytes-- = 0x80 | (cvalue & 0x3f);
  + cvalue >>= 6;
  + }
  +*utf8bytes = utf8_table2[i] | cvalue;
  +return i + 1;
  +}
  +
  +#endif
  +
  +
  +
  +/*************************************************
   *             Print character string             *
   *************************************************/


@@ -200,7 +345,7 @@

static int pchars(unsigned char *p, int length, FILE *f)
{
-int c;
+int c = 0;
int yield = 0;

   while (length-- > 0)
  @@ -406,8 +551,8 @@
   *         Byte flipping function                 *
   *************************************************/


-static long int
-byteflip(long int value, int n)
+static unsigned long int
+byteflip(unsigned long int value, int n)
{
if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
return ((value & 0x000000ff) << 24) |
@@ -420,6 +565,83 @@


   /*************************************************
  +*        Check match or recursion limit          *
  +*************************************************/
  +
  +static int
  +check_match_limit(pcre *re, pcre_extra *extra, uschar *bptr, int len,
  +  int start_offset, int options, int *use_offsets, int use_size_offsets,
  +  int flag, unsigned long int *limit, int errnumber, const char *msg)
  +{
  +int count;
  +int min = 0;
  +int mid = 64;
  +int max = -1;
  +
  +extra->flags |= flag;
  +
  +for (;;)
  +  {
  +  *limit = mid;
  +
  +  count = pcre_exec(re, extra, (char *)bptr, len, start_offset, options,
  +    use_offsets, use_size_offsets);
  +
  +  if (count == errnumber)
  +    {
  +    /* fprintf(outfile, "Testing %s limit = %d\n", msg, mid); */
  +    min = mid;
  +    mid = (mid == max - 1)? max : (max > 0)? (min + max)/2 : mid*2;
  +    }
  +
  +  else if (count >= 0 || count == PCRE_ERROR_NOMATCH ||
  +                         count == PCRE_ERROR_PARTIAL)
  +    {
  +    if (mid == min + 1)
  +      {
  +      fprintf(outfile, "Minimum %s limit = %d\n", msg, mid);
  +      break;
  +      }
  +    /* fprintf(outfile, "Testing %s limit = %d\n", msg, mid); */
  +    max = mid;
  +    mid = (min + mid)/2;
  +    }
  +  else break;    /* Some other error */
  +  }
  +
  +extra->flags &= ~flag;
  +return count;
  +}
  +
  +
  +
  +/*************************************************
  +*         Check newline indicator                *
  +*************************************************/
  +
  +/* This is used both at compile and run-time to check for <xxx> escapes, where
  +xxx is LF, CR, or CRLF. Print a message and return 0 if there is no match.
  +
  +Arguments:
  +  p           points after the leading '<'
  +  f           file for error message
  +
  +Returns:      appropriate PCRE_NEWLINE_xxx flags, or 0
  +*/
  +
  +static int
  +check_newline(uschar *p, FILE *f)
  +{
  +if (strncmp((char *)p, "cr>", 3) == 0) return PCRE_NEWLINE_CR;
  +if (strncmp((char *)p, "lf>", 3) == 0) return PCRE_NEWLINE_LF;
  +if (strncmp((char *)p, "crlf>", 5) == 0) return PCRE_NEWLINE_CRLF;
  +fprintf(f, "Unknown newline type at: <%s\n", p);
  +return 0;
  +}
  +
  +
  +
  +/*************************************************
   *                Main Program                    *
   *************************************************/


@@ -436,6 +658,7 @@
int timeit = 0;
int showinfo = 0;
int showstore = 0;
+int quiet = 0;
int size_offsets = 45;
int size_offsets_max;
int *offsets = NULL;
@@ -446,16 +669,23 @@
int done = 0;
int all_use_dfa = 0;
int yield = 0;
+int stack_size;
+
+/* These vectors store, end-to-end, a list of captured substring names. Assume
+that 1024 is plenty long enough for the few names we'll be testing. */
+
+uschar copynames[1024];
+uschar getnames[1024];

-unsigned char *buffer;
-unsigned char *dbuffer;
+uschar *copynamesptr;
+uschar *getnamesptr;

/* Get buffers from malloc() so that Electric Fence will check their misuse
-when I am debugging. */
+when I am debugging. They grow automatically when very long lines are read. */

-buffer = (unsigned char *)malloc(BUFFER_SIZE);
-dbuffer = (unsigned char *)malloc(DBUFFER_SIZE);
-pbuffer = (unsigned char *)malloc(PBUFFER_SIZE);
+buffer = (unsigned char *)malloc(buffer_size);
+dbuffer = (unsigned char *)malloc(buffer_size);
+pbuffer = (unsigned char *)malloc(buffer_size);

   /* The outfile variable is static so that new_malloc can use it. The _setmode()
   stuff is some magic that I don't understand, but which apparently does good
  @@ -476,6 +706,7 @@
     if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0)
       showstore = 1;
     else if (strcmp(argv[op], "-t") == 0) timeit = 1;
  +  else if (strcmp(argv[op], "-q") == 0) quiet = 1;
     else if (strcmp(argv[op], "-i") == 0) showinfo = 1;
     else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1;
   #if !defined NODFA
  @@ -488,6 +719,28 @@
       op++;
       argc--;
       }
  +  else if (strcmp(argv[op], "-S") == 0 && argc > 2 &&
  +      ((stack_size = get_value((unsigned char *)argv[op+1], &endptr)),
  +        *endptr == 0))
  +    {
  +#ifdef _WIN32
  +    printf("PCRE: -S not supported on this OS\n");
  +    exit(1);
  +#else
  +    int rc;
  +    struct rlimit rlim;
  +    getrlimit(RLIMIT_STACK, &rlim);
  +    rlim.rlim_cur = stack_size * 1024 * 1024;
  +    rc = setrlimit(RLIMIT_STACK, &rlim);
  +    if (rc != 0)
  +      {
  +    printf("PCRE: setrlimit() failed with error %d\n", rc);
  +    exit(1);
  +      }
  +    op++;
  +    argc--;
  +#endif
  +    }
   #if !defined NOPOSIX
     else if (strcmp(argv[op], "-p") == 0) posix = 1;
   #endif
  @@ -501,13 +754,16 @@
       (void)pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &rc);
       printf("  %sUnicode properties support\n", rc? "" : "No ");
       (void)pcre_config(PCRE_CONFIG_NEWLINE, &rc);
  -    printf("  Newline character is %s\n", (rc == '\r')? "CR" : "LF");
  +    printf("  Newline sequence is %s\n", (rc == '\r')? "CR" :
  +      (rc == '\n')? "LF" : "CRLF");
       (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc);
       printf("  Internal link size = %d\n", rc);
       (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc);
       printf("  POSIX malloc threshold = %d\n", rc);
       (void)pcre_config(PCRE_CONFIG_MATCH_LIMIT, &rc);
       printf("  Default match limit = %d\n", rc);
  +    (void)pcre_config(PCRE_CONFIG_MATCH_LIMIT_RECURSION, &rc);
  +    printf("  Default recursion depth limit = %d\n", rc);
       (void)pcre_config(PCRE_CONFIG_STACKRECURSE, &rc);
       printf("  Match recursion uses %s\n", rc? "stack" : "heap");
       exit(0);
  @@ -515,7 +771,7 @@
     else
       {
       printf("** Unknown or malformed option %s\n", argv[op]);
  -    printf("Usage:   pcretest [-d] [-i] [-o <n>] [-p] [-s] [-t] [<input> [<output>]]\n");
  +    printf("Usage:   pcretest [options] [<input> [<output>]]\n");
       printf("  -C     show PCRE compile-time options and exit\n");
       printf("  -d     debug: show compiled code; implies -i\n");
   #if !defined NODFA
  @@ -527,6 +783,7 @@
   #if !defined NOPOSIX
       printf("  -p     use POSIX interface\n");
   #endif
  +    printf("  -S <n> set stack size to <n> megabytes\n");
       printf("  -s     output store (memory) used information\n"
              "  -t     time compilation and execution\n");
       yield = 1;
  @@ -579,9 +836,9 @@
   pcre_stack_malloc = stack_malloc;
   pcre_stack_free = stack_free;


-/* Heading line, then prompt for first regex if stdin */
+/* Heading line unless quiet, then prompt for first regex if stdin */

-fprintf(outfile, "PCRE version %s\n\n", pcre_version());
+if (!quiet) fprintf(outfile, "PCRE version %s\n\n", pcre_version());

/* Main loop */

  @@ -613,7 +870,7 @@
     use_utf8 = 0;


     if (infile == stdin) printf("  re> ");
  -  if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) break;
  +  if (extend_inputline(infile, buffer) == NULL) break;
     if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
     fflush(outfile);


@@ -625,7 +882,7 @@

     if (*p == '<' && strchr((char *)(p+1), '<') == NULL)
       {
  -    unsigned long int magic;
  +    unsigned long int magic, get_options;
       uschar sbuf[8];
       FILE *f;


@@ -673,8 +930,8 @@

       /* Need to know if UTF-8 for printing data strings */


  -    new_info(re, NULL, PCRE_INFO_OPTIONS, &options);
  -    use_utf8 = (options & PCRE_UTF8) != 0;
  +    new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options);
  +    use_utf8 = (get_options & PCRE_UTF8) != 0;


       /* Now see if there is any following study data */


  @@ -728,16 +985,8 @@
         pp++;
         }
       if (*pp != 0) break;
  -
  -    len = BUFFER_SIZE - (pp - buffer);
  -    if (len < 256)
  -      {
  -      fprintf(outfile, "** Expression too long - missing delimiter?\n");
  -      goto SKIP_DATA;
  -      }
  -
       if (infile == stdin) printf("    > ");
  -    if (fgets((char *)pp, len, infile) == NULL)
  +    if ((pp = extend_inputline(infile, pp)) == NULL)
         {
         fprintf(outfile, "** Unexpected EOF\n");
         done = 1;
  @@ -783,6 +1032,7 @@
         case 'F': do_flip = 1; break;
         case 'G': do_G = 1; break;
         case 'I': do_showinfo = 1; break;
  +      case 'J': options |= PCRE_DUPNAMES; break;
         case 'M': log_store = 1; break;
         case 'N': options |= PCRE_NO_AUTO_CAPTURE; break;


  @@ -817,6 +1067,15 @@
         *pp = 0;
         break;


  +      case '<':
  +        {
  +        int x = check_newline(pp, outfile);
  +        if (x == 0) goto SKIP_DATA;
  +        options |= x;
  +        while (*pp++ != '>');
  +        }
  +      break;
  +
         case '\r':                      /* So that it works in Windows */
         case '\n':
         case ' ':
  @@ -841,6 +1100,9 @@
       if ((options & PCRE_CASELESS) != 0) cflags |= REG_ICASE;
       if ((options & PCRE_MULTILINE) != 0) cflags |= REG_NEWLINE;
       if ((options & PCRE_DOTALL) != 0) cflags |= REG_DOTALL;
  +    if ((options & PCRE_NO_AUTO_CAPTURE) != 0) cflags |= REG_NOSUB;
  +    if ((options & PCRE_UTF8) != 0) cflags |= REG_UTF8;
  +
       rc = regcomp(&preg, (char *)p, cflags);


       /* Compilation failed; go back for another re, skipping to blank line
  @@ -848,7 +1110,7 @@


       if (rc != 0)
         {
  -      (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
  +      (void)regerror(rc, &preg, (char *)buffer, buffer_size);
         fprintf(outfile, "Failed: POSIX code %d: %s\n", rc, buffer);
         goto SKIP_DATA;
         }
  @@ -889,7 +1151,7 @@
           {
           for (;;)
             {
  -          if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
  +          if (extend_inputline(infile, buffer) == NULL)
               {
               done = 1;
               goto CONTINUE;
  @@ -990,7 +1252,7 @@
         if (do_debug)
           {
           fprintf(outfile, "------------------------------------------------------------------\n");
  -        _pcre_printint(re, outfile);
  +        pcre_printint(re, outfile);
           }


         new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options);
  @@ -1050,13 +1312,13 @@
         if (do_flip)
           {
           all_options = byteflip(all_options, sizeof(all_options));
  -        }
  +         }


         if ((all_options & PCRE_NOPARTIAL) != 0)
           fprintf(outfile, "Partial matching not supported\n");


         if (get_options == 0) fprintf(outfile, "No options\n");
  -        else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s%s\n",
  +        else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
             ((get_options & PCRE_ANCHORED) != 0)? " anchored" : "",
             ((get_options & PCRE_CASELESS) != 0)? " caseless" : "",
             ((get_options & PCRE_EXTENDED) != 0)? " extended" : "",
  @@ -1066,15 +1328,32 @@
             ((get_options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
             ((get_options & PCRE_EXTRA) != 0)? " extra" : "",
             ((get_options & PCRE_UNGREEDY) != 0)? " ungreedy" : "",
  +          ((get_options & PCRE_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "",
             ((get_options & PCRE_UTF8) != 0)? " utf8" : "",
  -          ((get_options & PCRE_NO_UTF8_CHECK) != 0)? " no_utf8_check" : "");
  +          ((get_options & PCRE_NO_UTF8_CHECK) != 0)? " no_utf8_check" : "",
  +          ((get_options & PCRE_DUPNAMES) != 0)? " dupnames" : "");
  +
  +      switch (get_options & PCRE_NEWLINE_CRLF)
  +        {
  +        case PCRE_NEWLINE_CR:
  +        fprintf(outfile, "Forced newline sequence: CR\n");
  +        break;
  +
  +        case PCRE_NEWLINE_LF:
  +        fprintf(outfile, "Forced newline sequence: LF\n");
  +        break;


  -      if (((((real_pcre *)re)->options) & PCRE_ICHANGED) != 0)
  -        fprintf(outfile, "Case state changes\n");
  +        case PCRE_NEWLINE_CRLF:
  +        fprintf(outfile, "Forced newline sequence: CRLF\n");
  +        break;
  +
  +        default:
  +        break;
  +        }


         if (first_char == -1)
           {
  -        fprintf(outfile, "First char at start or follows \\n\n");
  +        fprintf(outfile, "First char at start or follows newline\n");
           }
         else if (first_char < 0)
           {
  @@ -1211,8 +1490,8 @@


     for (;;)
       {
  -    unsigned char *q;
  -    unsigned char *bptr = dbuffer;
  +    uschar *q;
  +    uschar *bptr = dbuffer;
       int *use_offsets = offsets;
       int use_size_offsets = size_offsets;
       int callout_data = 0;
  @@ -1229,6 +1508,12 @@


       options = 0;


  +    *copynames = 0;
  +    *getnames = 0;
  +
  +    copynamesptr = copynames;
  +    getnamesptr = getnames;
  +
       pcre_callout = callout;
       first_callout = 1;
       callout_extra = 0;
  @@ -1237,15 +1522,24 @@
       callout_fail_id = -1;
       show_malloc = 0;


  -    if (infile == stdin) printf("data> ");
  -    if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
  +    if (extra != NULL) extra->flags &=
  +      ~(PCRE_EXTRA_MATCH_LIMIT|PCRE_EXTRA_MATCH_LIMIT_RECURSION);
  +
  +    len = 0;
  +    for (;;)
         {
  -      done = 1;
  -      goto CONTINUE;
  +      if (infile == stdin) printf("data> ");
  +      if (extend_inputline(infile, buffer + len) == NULL)
  +        {
  +        if (len > 0) break;
  +        done = 1;
  +        goto CONTINUE;
  +        }
  +      if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
  +      len = (int)strlen((char *)buffer);
  +      if (buffer[len-1] == '\n') break;
         }
  -    if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);


  -    len = (int)strlen((char *)buffer);
       while (len > 0 && isspace(buffer[len-1])) len--;
       buffer[len] = 0;
       if (len == 0) break;
  @@ -1275,6 +1569,17 @@
           c -= '0';
           while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9')
             c = c * 8 + *p++ - '0';
  +
  +#if !defined NOUTF8
  +        if (use_utf8 && c > 255)
  +          {
  +          unsigned char buff8[8];
  +          int ii, utn;
  +          utn = ord2utf8(c, buff8);
  +          for (ii = 0; ii < utn - 1; ii++) *q++ = buff8[ii];
  +          c = buff8[ii];   /* Last byte */
  +          }
  +#endif
           break;


           case 'x':
  @@ -1292,7 +1597,7 @@
               {
               unsigned char buff8[8];
               int ii, utn;
  -            utn = _pcre_ord2utf8(c, buff8);
  +            utn = ord2utf8(c, buff8);
               for (ii = 0; ii < utn - 1; ii++) *q++ = buff8[ii];
               c = buff8[ii];   /* Last byte */
               p = pt + 1;
  @@ -1336,14 +1641,14 @@
             }
           else if (isalnum(*p))
             {
  -          uschar name[256];
  -          uschar *npp = name;
  +          uschar *npp = copynamesptr;
             while (isalnum(*p)) *npp++ = *p++;
  +          *npp++ = 0;
             *npp = 0;
  -          n = pcre_get_stringnumber(re, (char *)name);
  +          n = pcre_get_stringnumber(re, (char *)copynamesptr);
             if (n < 0)
  -            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
  -          else copystrings |= 1 << n;
  +            fprintf(outfile, "no parentheses with name \"%s\"\n", copynamesptr);
  +          copynamesptr = npp;
             }
           else if (*p == '+')
             {
  @@ -1404,14 +1709,14 @@
             }
           else if (isalnum(*p))
             {
  -          uschar name[256];
  -          uschar *npp = name;
  +          uschar *npp = getnamesptr;
             while (isalnum(*p)) *npp++ = *p++;
  +          *npp++ = 0;
             *npp = 0;
  -          n = pcre_get_stringnumber(re, (char *)name);
  +          n = pcre_get_stringnumber(re, (char *)getnamesptr);
             if (n < 0)
  -            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
  -          else getstrings |= 1 << n;
  +            fprintf(outfile, "no parentheses with name \"%s\"\n", getnamesptr);
  +          getnamesptr = npp;
             }
           continue;


  @@ -1450,6 +1755,28 @@
           options |= PCRE_PARTIAL;
           continue;


  +        case 'Q':
  +        while(isdigit(*p)) n = n * 10 + *p++ - '0';
  +        if (extra == NULL)
  +          {
  +          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
  +          extra->flags = 0;
  +          }
  +        extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
  +        extra->match_limit_recursion = n;
  +        continue;
  +
  +        case 'q':
  +        while(isdigit(*p)) n = n * 10 + *p++ - '0';
  +        if (extra == NULL)
  +          {
  +          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
  +          extra->flags = 0;
  +          }
  +        extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
  +        extra->match_limit = n;
  +        continue;
  +
   #if !defined NODFA
           case 'R':
           options |= PCRE_DFA_RESTART;
  @@ -1467,6 +1794,15 @@
           case '?':
           options |= PCRE_NO_UTF8_CHECK;
           continue;
  +
  +        case '<':
  +          {
  +          int x = check_newline(p, outfile);
  +          if (x == 0) goto NEXT_DATA;
  +          options |= x;
  +          while (*p++ != '>');
  +          }
  +        continue;
           }
         *q++ = c;
         }
  @@ -1497,9 +1833,14 @@


         if (rc != 0)
           {
  -        (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
  +        (void)regerror(rc, &preg, (char *)buffer, buffer_size);
           fprintf(outfile, "No match: POSIX code %d: %s\n", rc, buffer);
           }
  +      else if ((((const pcre *)preg.re_pcre)->options & PCRE_NO_AUTO_CAPTURE)
  +              != 0)
  +        {
  +        fprintf(outfile, "Matched with REG_NOSUB\n");
  +        }
         else
           {
           size_t i;
  @@ -1560,48 +1901,26 @@
           }


         /* If find_match_limit is set, we want to do repeated matches with
  -      varying limits in order to find the minimum value. */
  +      varying limits in order to find the minimum value for the match limit and
  +      for the recursion limit. */


         if (find_match_limit)
           {
  -        int min = 0;
  -        int mid = 64;
  -        int max = -1;
  -
           if (extra == NULL)
             {
             extra = (pcre_extra *)malloc(sizeof(pcre_extra));
             extra->flags = 0;
             }
  -        extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
  -
  -        for (;;)
  -          {
  -          extra->match_limit = mid;
  -          count = pcre_exec(re, extra, (char *)bptr, len, start_offset,
  -            options | g_notempty, use_offsets, use_size_offsets);
  -          if (count == PCRE_ERROR_MATCHLIMIT)
  -            {
  -            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
  -            min = mid;
  -            mid = (mid == max - 1)? max : (max > 0)? (min + max)/2 : mid*2;
  -            }
  -          else if (count >= 0 || count == PCRE_ERROR_NOMATCH ||
  -                                 count == PCRE_ERROR_PARTIAL)
  -            {
  -            if (mid == min + 1)
  -              {
  -              fprintf(outfile, "Minimum match limit = %d\n", mid);
  -              break;
  -              }
  -            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
  -            max = mid;
  -            mid = (min + mid)/2;
  -            }
  -          else break;    /* Some other error */
  -          }


  -        extra->flags &= ~PCRE_EXTRA_MATCH_LIMIT;
  +        (void)check_match_limit(re, extra, bptr, len, start_offset,
  +          options|g_notempty, use_offsets, use_size_offsets,
  +          PCRE_EXTRA_MATCH_LIMIT, &(extra->match_limit),
  +          PCRE_ERROR_MATCHLIMIT, "match()");
  +
  +        count = check_match_limit(re, extra, bptr, len, start_offset,
  +          options|g_notempty, use_offsets, use_size_offsets,
  +          PCRE_EXTRA_MATCH_LIMIT_RECURSION, &(extra->match_limit_recursion),
  +          PCRE_ERROR_RECURSIONLIMIT, "match() recursion");
           }


         /* If callout_data is set, use the interface with additional data */
  @@ -1681,7 +2000,7 @@
             {
             if ((copystrings & (1 << i)) != 0)
               {
  -            char copybuffer[16];
  +            char copybuffer[256];
               int rc = pcre_copy_substring((char *)bptr, use_offsets, count,
                 i, copybuffer, sizeof(copybuffer));
               if (rc < 0)
  @@ -1691,6 +2010,19 @@
               }
             }


  +        for (copynamesptr = copynames;
  +             *copynamesptr != 0;
  +             copynamesptr += (int)strlen((char*)copynamesptr) + 1)
  +          {
  +          char copybuffer[256];
  +          int rc = pcre_copy_named_substring(re, (char *)bptr, use_offsets,
  +            count, (char *)copynamesptr, copybuffer, sizeof(copybuffer));
  +          if (rc < 0)
  +            fprintf(outfile, "copy substring %s failed %d\n", copynamesptr, rc);
  +          else
  +            fprintf(outfile, "  C %s (%d) %s\n", copybuffer, rc, copynamesptr);
  +          }
  +
           for (i = 0; i < 32; i++)
             {
             if ((getstrings & (1 << i)) != 0)
  @@ -1703,12 +2035,27 @@
               else
                 {
                 fprintf(outfile, "%2dG %s (%d)\n", i, substring, rc);
  -              /* free((void *)substring); */
                 pcre_free_substring(substring);
                 }
               }
             }


  +        for (getnamesptr = getnames;
  +             *getnamesptr != 0;
  +             getnamesptr += (int)strlen((char*)getnamesptr) + 1)
  +          {
  +          const char *substring;
  +          int rc = pcre_get_named_substring(re, (char *)bptr, use_offsets,
  +            count, (char *)getnamesptr, &substring);
  +          if (rc < 0)
  +            fprintf(outfile, "copy substring %s failed %d\n", getnamesptr, rc);
  +          else
  +            {
  +            fprintf(outfile, "  G %s (%d) %s\n", substring, rc, getnamesptr);
  +            pcre_free_substring(substring);
  +            }
  +          }
  +
           if (getlist)
             {
             const char **stringlist;
  @@ -1808,6 +2155,8 @@
           len -= use_offsets[1];
           }
         }  /* End of loop for /g and /G */
  +
  +    NEXT_DATA: continue;
       }    /* End of loop for data lines */


     CONTINUE:


  Index: ucp.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/pcre/ucp.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ucp.h    8 Aug 2005 10:22:14 -0000    1.2
  +++ ucp.h    7 Nov 2006 16:50:36 -0000    1.3
  @@ -1,14 +1,16 @@
  -/* $Cambridge: exim/exim-src/src/pcre/ucp.h,v 1.2 2005/08/08 10:22:14 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/pcre/ucp.h,v 1.3 2006/11/07 16:50:36 ph10 Exp $ */


   /*************************************************
  -*     libucp - Unicode Property Table handler    *
  +*          Unicode Property Table handler        *
   *************************************************/


-
#ifndef _UCP_H
#define _UCP_H

-/* These are the character categories that are returned by ucp_findchar */
+/* This file contains definitions of the property values that are returned by
+the function _pcre_ucp_findprop(). */
+
+/* These are the general character categories. */

   enum {
     ucp_C,     /* Other */
  @@ -20,7 +22,7 @@
     ucp_Z      /* Separator */
   };


-/* These are the detailed character types that are returned by ucp_findchar */
+/* These are the particular character types. */

   enum {
     ucp_Cc,    /* Control */
  @@ -55,7 +57,71 @@
     ucp_Zs     /* Space separator */
   };


-extern int ucp_findchar(const int, int *, int *);
+/* These are the script identifications. */
+
+enum {
+ ucp_Arabic,
+ ucp_Armenian,
+ ucp_Bengali,
+ ucp_Bopomofo,
+ ucp_Braille,
+ ucp_Buginese,
+ ucp_Buhid,
+ ucp_Canadian_Aboriginal,
+ ucp_Cherokee,
+ ucp_Common,
+ ucp_Coptic,
+ ucp_Cypriot,
+ ucp_Cyrillic,
+ ucp_Deseret,
+ ucp_Devanagari,
+ ucp_Ethiopic,
+ ucp_Georgian,
+ ucp_Glagolitic,
+ ucp_Gothic,
+ ucp_Greek,
+ ucp_Gujarati,
+ ucp_Gurmukhi,
+ ucp_Han,
+ ucp_Hangul,
+ ucp_Hanunoo,
+ ucp_Hebrew,
+ ucp_Hiragana,
+ ucp_Inherited,
+ ucp_Kannada,
+ ucp_Katakana,
+ ucp_Kharoshthi,
+ ucp_Khmer,
+ ucp_Lao,
+ ucp_Latin,
+ ucp_Limbu,
+ ucp_Linear_B,
+ ucp_Malayalam,
+ ucp_Mongolian,
+ ucp_Myanmar,
+ ucp_New_Tai_Lue,
+ ucp_Ogham,
+ ucp_Old_Italic,
+ ucp_Old_Persian,
+ ucp_Oriya,
+ ucp_Osmanya,
+ ucp_Runic,
+ ucp_Shavian,
+ ucp_Sinhala,
+ ucp_Syloti_Nagri,
+ ucp_Syriac,
+ ucp_Tagalog,
+ ucp_Tagbanwa,
+ ucp_Tai_Le,
+ ucp_Tamil,
+ ucp_Telugu,
+ ucp_Thaana,
+ ucp_Thai,
+ ucp_Tibetan,
+ ucp_Tifinagh,
+ ucp_Ugaritic,
+ ucp_Yi
+};

#endif