tools/pcre/pcre_dfa_exec.c
author Nicholas Hastings <skamonkey@gmail.com>
Sun Jul 15 12:31:06 2012 -0400 (2012-07-15)
changeset 3579 6d730190a3e4
parent 2762 d2d467bf1b5a
child 3831 babd0eee3c5e
permissions -rw-r--r--
Added missing files to each core and logic makefiles (NPOTB).
dvander@2762
     1
/*************************************************
dvander@2762
     2
*      Perl-Compatible Regular Expressions       *
dvander@2762
     3
*************************************************/
dvander@2762
     4
dvander@2762
     5
/* PCRE is a library of functions to support regular expressions whose syntax
dvander@2762
     6
and semantics are as close as possible to those of the Perl 5 language (but see
dvander@2762
     7
below for why this module is different).
dvander@2762
     8
dvander@2762
     9
                       Written by Philip Hazel
dvander@2762
    10
           Copyright (c) 1997-2009 University of Cambridge
dvander@2762
    11
dvander@2762
    12
-----------------------------------------------------------------------------
dvander@2762
    13
Redistribution and use in source and binary forms, with or without
dvander@2762
    14
modification, are permitted provided that the following conditions are met:
dvander@2762
    15
dvander@2762
    16
    * Redistributions of source code must retain the above copyright notice,
dvander@2762
    17
      this list of conditions and the following disclaimer.
dvander@2762
    18
dvander@2762
    19
    * Redistributions in binary form must reproduce the above copyright
dvander@2762
    20
      notice, this list of conditions and the following disclaimer in the
dvander@2762
    21
      documentation and/or other materials provided with the distribution.
dvander@2762
    22
dvander@2762
    23
    * Neither the name of the University of Cambridge nor the names of its
dvander@2762
    24
      contributors may be used to endorse or promote products derived from
dvander@2762
    25
      this software without specific prior written permission.
dvander@2762
    26
dvander@2762
    27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
dvander@2762
    28
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
dvander@2762
    29
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
dvander@2762
    30
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
dvander@2762
    31
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
dvander@2762
    32
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
dvander@2762
    33
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
dvander@2762
    34
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
dvander@2762
    35
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
dvander@2762
    36
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
dvander@2762
    37
POSSIBILITY OF SUCH DAMAGE.
dvander@2762
    38
-----------------------------------------------------------------------------
dvander@2762
    39
*/
dvander@2762
    40
dvander@2762
    41
dvander@2762
    42
/* This module contains the external function pcre_dfa_exec(), which is an
dvander@2762
    43
alternative matching function that uses a sort of DFA algorithm (not a true
dvander@2762
    44
FSM). This is NOT Perl- compatible, but it has advantages in certain
dvander@2762
    45
applications. */
dvander@2762
    46
dvander@2762
    47
dvander@2762
    48
#ifdef HAVE_CONFIG_H
dvander@2762
    49
#include "config.h"
dvander@2762
    50
#endif
dvander@2762
    51
dvander@2762
    52
#define NLBLOCK md             /* Block containing newline information */
dvander@2762
    53
#define PSSTART start_subject  /* Field containing processed string start */
dvander@2762
    54
#define PSEND   end_subject    /* Field containing processed string end */
dvander@2762
    55
dvander@2762
    56
#include "pcre_internal.h"
dvander@2762
    57
dvander@2762
    58
dvander@2762
    59
/* For use to indent debugging output */
dvander@2762
    60
dvander@2762
    61
#define SP "                   "
dvander@2762
    62
dvander@2762
    63
dvander@2762
    64
/*************************************************
dvander@2762
    65
*      Code parameters and static tables         *
dvander@2762
    66
*************************************************/
dvander@2762
    67
dvander@2762
    68
/* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes
dvander@2762
    69
into others, under special conditions. A gap of 20 between the blocks should be
dvander@2762
    70
enough. The resulting opcodes don't have to be less than 256 because they are
dvander@2762
    71
never stored, so we push them well clear of the normal opcodes. */
dvander@2762
    72
dvander@2762
    73
#define OP_PROP_EXTRA       300
dvander@2762
    74
#define OP_EXTUNI_EXTRA     320
dvander@2762
    75
#define OP_ANYNL_EXTRA      340
dvander@2762
    76
#define OP_HSPACE_EXTRA     360
dvander@2762
    77
#define OP_VSPACE_EXTRA     380
dvander@2762
    78
dvander@2762
    79
dvander@2762
    80
/* This table identifies those opcodes that are followed immediately by a
dvander@2762
    81
character that is to be tested in some way. This makes is possible to
dvander@2762
    82
centralize the loading of these characters. In the case of Type * etc, the
dvander@2762
    83
"character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a
dvander@2762
    84
small value. ***NOTE*** If the start of this table is modified, the two tables
dvander@2762
    85
that follow must also be modified. */
dvander@2762
    86
dvander@2762
    87
static const uschar coptable[] = {
dvander@2762
    88
  0,                             /* End                                    */
dvander@2762
    89
  0, 0, 0, 0, 0,                 /* \A, \G, \K, \B, \b                     */
dvander@2762
    90
  0, 0, 0, 0, 0, 0,              /* \D, \d, \S, \s, \W, \w                 */
dvander@2762
    91
  0, 0, 0,                       /* Any, AllAny, Anybyte                   */
dvander@2762
    92
  0, 0, 0,                       /* NOTPROP, PROP, EXTUNI                  */
dvander@2762
    93
  0, 0, 0, 0, 0,                 /* \R, \H, \h, \V, \v                     */
dvander@2762
    94
  0, 0, 0, 0, 0,                 /* \Z, \z, Opt, ^, $                      */
dvander@2762
    95
  1,                             /* Char                                   */
dvander@2762
    96
  1,                             /* Charnc                                 */
dvander@2762
    97
  1,                             /* not                                    */
dvander@2762
    98
  /* Positive single-char repeats                                          */
dvander@2762
    99
  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */
dvander@2762
   100
  3, 3, 3,                       /* upto, minupto, exact                   */
dvander@2762
   101
  1, 1, 1, 3,                    /* *+, ++, ?+, upto+                      */
dvander@2762
   102
  /* Negative single-char repeats - only for chars < 256                   */
dvander@2762
   103
  1, 1, 1, 1, 1, 1,              /* NOT *, *?, +, +?, ?, ??                */
dvander@2762
   104
  3, 3, 3,                       /* NOT upto, minupto, exact               */
dvander@2762
   105
  1, 1, 1, 3,                    /* NOT *+, ++, ?+, updo+                  */
dvander@2762
   106
  /* Positive type repeats                                                 */
dvander@2762
   107
  1, 1, 1, 1, 1, 1,              /* Type *, *?, +, +?, ?, ??               */
dvander@2762
   108
  3, 3, 3,                       /* Type upto, minupto, exact              */
dvander@2762
   109
  1, 1, 1, 3,                    /* Type *+, ++, ?+, upto+                 */
dvander@2762
   110
  /* Character class & ref repeats                                         */
dvander@2762
   111
  0, 0, 0, 0, 0, 0,              /* *, *?, +, +?, ?, ??                    */
dvander@2762
   112
  0, 0,                          /* CRRANGE, CRMINRANGE                    */
dvander@2762
   113
  0,                             /* CLASS                                  */
dvander@2762
   114
  0,                             /* NCLASS                                 */
dvander@2762
   115
  0,                             /* XCLASS - variable length               */
dvander@2762
   116
  0,                             /* REF                                    */
dvander@2762
   117
  0,                             /* RECURSE                                */
dvander@2762
   118
  0,                             /* CALLOUT                                */
dvander@2762
   119
  0,                             /* Alt                                    */
dvander@2762
   120
  0,                             /* Ket                                    */
dvander@2762
   121
  0,                             /* KetRmax                                */
dvander@2762
   122
  0,                             /* KetRmin                                */
dvander@2762
   123
  0,                             /* Assert                                 */
dvander@2762
   124
  0,                             /* Assert not                             */
dvander@2762
   125
  0,                             /* Assert behind                          */
dvander@2762
   126
  0,                             /* Assert behind not                      */
dvander@2762
   127
  0,                             /* Reverse                                */
dvander@2762
   128
  0, 0, 0, 0,                    /* ONCE, BRA, CBRA, COND                  */
dvander@2762
   129
  0, 0, 0,                       /* SBRA, SCBRA, SCOND                     */
dvander@2762
   130
  0,                             /* CREF                                   */
dvander@2762
   131
  0,                             /* RREF                                   */
dvander@2762
   132
  0,                             /* DEF                                    */
dvander@2762
   133
  0, 0,                          /* BRAZERO, BRAMINZERO                    */
dvander@2762
   134
  0, 0, 0, 0,                    /* PRUNE, SKIP, THEN, COMMIT              */
dvander@2762
   135
  0, 0, 0                        /* FAIL, ACCEPT, SKIPZERO                 */
dvander@2762
   136
};
dvander@2762
   137
dvander@2762
   138
/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
dvander@2762
   139
and \w */
dvander@2762
   140
dvander@2762
   141
static const uschar toptable1[] = {
dvander@2762
   142
  0, 0, 0, 0, 0, 0,
dvander@2762
   143
  ctype_digit, ctype_digit,
dvander@2762
   144
  ctype_space, ctype_space,
dvander@2762
   145
  ctype_word,  ctype_word,
dvander@2762
   146
  0, 0                            /* OP_ANY, OP_ALLANY */
dvander@2762
   147
};
dvander@2762
   148
dvander@2762
   149
static const uschar toptable2[] = {
dvander@2762
   150
  0, 0, 0, 0, 0, 0,
dvander@2762
   151
  ctype_digit, 0,
dvander@2762
   152
  ctype_space, 0,
dvander@2762
   153
  ctype_word,  0,
dvander@2762
   154
  1, 1                            /* OP_ANY, OP_ALLANY */
dvander@2762
   155
};
dvander@2762
   156
dvander@2762
   157
dvander@2762
   158
/* Structure for holding data about a particular state, which is in effect the
dvander@2762
   159
current data for an active path through the match tree. It must consist
dvander@2762
   160
entirely of ints because the working vector we are passed, and which we put
dvander@2762
   161
these structures in, is a vector of ints. */
dvander@2762
   162
dvander@2762
   163
typedef struct stateblock {
dvander@2762
   164
  int offset;                     /* Offset to opcode */
dvander@2762
   165
  int count;                      /* Count for repeats */
dvander@2762
   166
  int ims;                        /* ims flag bits */
dvander@2762
   167
  int data;                       /* Some use extra data */
dvander@2762
   168
} stateblock;
dvander@2762
   169
dvander@2762
   170
#define INTS_PER_STATEBLOCK  (sizeof(stateblock)/sizeof(int))
dvander@2762
   171
dvander@2762
   172
dvander@2762
   173
#ifdef DEBUG
dvander@2762
   174
/*************************************************
dvander@2762
   175
*             Print character string             *
dvander@2762
   176
*************************************************/
dvander@2762
   177
dvander@2762
   178
/* Character string printing function for debugging.
dvander@2762
   179
dvander@2762
   180
Arguments:
dvander@2762
   181
  p            points to string
dvander@2762
   182
  length       number of bytes
dvander@2762
   183
  f            where to print
dvander@2762
   184
dvander@2762
   185
Returns:       nothing
dvander@2762
   186
*/
dvander@2762
   187
dvander@2762
   188
static void
dvander@2762
   189
pchars(unsigned char *p, int length, FILE *f)
dvander@2762
   190
{
dvander@2762
   191
int c;
dvander@2762
   192
while (length-- > 0)
dvander@2762
   193
  {
dvander@2762
   194
  if (isprint(c = *(p++)))
dvander@2762
   195
    fprintf(f, "%c", c);
dvander@2762
   196
  else
dvander@2762
   197
    fprintf(f, "\\x%02x", c);
dvander@2762
   198
  }
dvander@2762
   199
}
dvander@2762
   200
#endif
dvander@2762
   201
dvander@2762
   202
dvander@2762
   203
dvander@2762
   204
/*************************************************
dvander@2762
   205
*    Execute a Regular Expression - DFA engine   *
dvander@2762
   206
*************************************************/
dvander@2762
   207
dvander@2762
   208
/* This internal function applies a compiled pattern to a subject string,
dvander@2762
   209
starting at a given point, using a DFA engine. This function is called from the
dvander@2762
   210
external one, possibly multiple times if the pattern is not anchored. The
dvander@2762
   211
function calls itself recursively for some kinds of subpattern.
dvander@2762
   212
dvander@2762
   213
Arguments:
dvander@2762
   214
  md                the match_data block with fixed information
dvander@2762
   215
  this_start_code   the opening bracket of this subexpression's code
dvander@2762
   216
  current_subject   where we currently are in the subject string
dvander@2762
   217
  start_offset      start offset in the subject string
dvander@2762
   218
  offsets           vector to contain the matching string offsets
dvander@2762
   219
  offsetcount       size of same
dvander@2762
   220
  workspace         vector of workspace
dvander@2762
   221
  wscount           size of same
dvander@2762
   222
  ims               the current ims flags
dvander@2762
   223
  rlevel            function call recursion level
dvander@2762
   224
  recursing         regex recursive call level
dvander@2762
   225
dvander@2762
   226
Returns:            > 0 => number of match offset pairs placed in offsets
dvander@2762
   227
                    = 0 => offsets overflowed; longest matches are present
dvander@2762
   228
                     -1 => failed to match
dvander@2762
   229
                   < -1 => some kind of unexpected problem
dvander@2762
   230
dvander@2762
   231
The following macros are used for adding states to the two state vectors (one
dvander@2762
   232
for the current character, one for the following character). */
dvander@2762
   233
dvander@2762
   234
#define ADD_ACTIVE(x,y) \
dvander@2762
   235
  if (active_count++ < wscount) \
dvander@2762
   236
    { \
dvander@2762
   237
    next_active_state->offset = (x); \
dvander@2762
   238
    next_active_state->count  = (y); \
dvander@2762
   239
    next_active_state->ims    = ims; \
dvander@2762
   240
    next_active_state++; \
dvander@2762
   241
    DPRINTF(("%.*sADD_ACTIVE(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \
dvander@2762
   242
    } \
dvander@2762
   243
  else return PCRE_ERROR_DFA_WSSIZE
dvander@2762
   244
dvander@2762
   245
#define ADD_ACTIVE_DATA(x,y,z) \
dvander@2762
   246
  if (active_count++ < wscount) \
dvander@2762
   247
    { \
dvander@2762
   248
    next_active_state->offset = (x); \
dvander@2762
   249
    next_active_state->count  = (y); \
dvander@2762
   250
    next_active_state->ims    = ims; \
dvander@2762
   251
    next_active_state->data   = (z); \
dvander@2762
   252
    next_active_state++; \
dvander@2762
   253
    DPRINTF(("%.*sADD_ACTIVE_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \
dvander@2762
   254
    } \
dvander@2762
   255
  else return PCRE_ERROR_DFA_WSSIZE
dvander@2762
   256
dvander@2762
   257
#define ADD_NEW(x,y) \
dvander@2762
   258
  if (new_count++ < wscount) \
dvander@2762
   259
    { \
dvander@2762
   260
    next_new_state->offset = (x); \
dvander@2762
   261
    next_new_state->count  = (y); \
dvander@2762
   262
    next_new_state->ims    = ims; \
dvander@2762
   263
    next_new_state++; \
dvander@2762
   264
    DPRINTF(("%.*sADD_NEW(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \
dvander@2762
   265
    } \
dvander@2762
   266
  else return PCRE_ERROR_DFA_WSSIZE
dvander@2762
   267
dvander@2762
   268
#define ADD_NEW_DATA(x,y,z) \
dvander@2762
   269
  if (new_count++ < wscount) \
dvander@2762
   270
    { \
dvander@2762
   271
    next_new_state->offset = (x); \
dvander@2762
   272
    next_new_state->count  = (y); \
dvander@2762
   273
    next_new_state->ims    = ims; \
dvander@2762
   274
    next_new_state->data   = (z); \
dvander@2762
   275
    next_new_state++; \
dvander@2762
   276
    DPRINTF(("%.*sADD_NEW_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \
dvander@2762
   277
    } \
dvander@2762
   278
  else return PCRE_ERROR_DFA_WSSIZE
dvander@2762
   279
dvander@2762
   280
/* And now, here is the code */
dvander@2762
   281
dvander@2762
   282
static int
dvander@2762
   283
internal_dfa_exec(
dvander@2762
   284
  dfa_match_data *md,
dvander@2762
   285
  const uschar *this_start_code,
dvander@2762
   286
  const uschar *current_subject,
dvander@2762
   287
  int start_offset,
dvander@2762
   288
  int *offsets,
dvander@2762
   289
  int offsetcount,
dvander@2762
   290
  int *workspace,
dvander@2762
   291
  int wscount,
dvander@2762
   292
  int ims,
dvander@2762
   293
  int  rlevel,
dvander@2762
   294
  int  recursing)
dvander@2762
   295
{
dvander@2762
   296
stateblock *active_states, *new_states, *temp_states;
dvander@2762
   297
stateblock *next_active_state, *next_new_state;
dvander@2762
   298
dvander@2762
   299
const uschar *ctypes, *lcc, *fcc;
dvander@2762
   300
const uschar *ptr;
dvander@2762
   301
const uschar *end_code, *first_op;
dvander@2762
   302
dvander@2762
   303
int active_count, new_count, match_count;
dvander@2762
   304
dvander@2762
   305
/* Some fields in the md block are frequently referenced, so we load them into
dvander@2762
   306
independent variables in the hope that this will perform better. */
dvander@2762
   307
dvander@2762
   308
const uschar *start_subject = md->start_subject;
dvander@2762
   309
const uschar *end_subject = md->end_subject;
dvander@2762
   310
const uschar *start_code = md->start_code;
dvander@2762
   311
dvander@2762
   312
#ifdef SUPPORT_UTF8
dvander@2762
   313
BOOL utf8 = (md->poptions & PCRE_UTF8) != 0;
dvander@2762
   314
#else
dvander@2762
   315
BOOL utf8 = FALSE;
dvander@2762
   316
#endif
dvander@2762
   317
dvander@2762
   318
rlevel++;
dvander@2762
   319
offsetcount &= (-2);
dvander@2762
   320
dvander@2762
   321
wscount -= 2;
dvander@2762
   322
wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) /
dvander@2762
   323
          (2 * INTS_PER_STATEBLOCK);
dvander@2762
   324
dvander@2762
   325
DPRINTF(("\n%.*s---------------------\n"
dvander@2762
   326
  "%.*sCall to internal_dfa_exec f=%d r=%d\n",
dvander@2762
   327
  rlevel*2-2, SP, rlevel*2-2, SP, rlevel, recursing));
dvander@2762
   328
dvander@2762
   329
ctypes = md->tables + ctypes_offset;
dvander@2762
   330
lcc = md->tables + lcc_offset;
dvander@2762
   331
fcc = md->tables + fcc_offset;
dvander@2762
   332
dvander@2762
   333
match_count = PCRE_ERROR_NOMATCH;   /* A negative number */
dvander@2762
   334
dvander@2762
   335
active_states = (stateblock *)(workspace + 2);
dvander@2762
   336
next_new_state = new_states = active_states + wscount;
dvander@2762
   337
new_count = 0;
dvander@2762
   338
dvander@2762
   339
first_op = this_start_code + 1 + LINK_SIZE +
dvander@2762
   340
  ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0);
dvander@2762
   341
dvander@2762
   342
/* The first thing in any (sub) pattern is a bracket of some sort. Push all
dvander@2762
   343
the alternative states onto the list, and find out where the end is. This
dvander@2762
   344
makes is possible to use this function recursively, when we want to stop at a
dvander@2762
   345
matching internal ket rather than at the end.
dvander@2762
   346
dvander@2762
   347
If the first opcode in the first alternative is OP_REVERSE, we are dealing with
dvander@2762
   348
a backward assertion. In that case, we have to find out the maximum amount to
dvander@2762
   349
move back, and set up each alternative appropriately. */
dvander@2762
   350
dvander@2762
   351
if (*first_op == OP_REVERSE)
dvander@2762
   352
  {
dvander@2762
   353
  int max_back = 0;
dvander@2762
   354
  int gone_back;
dvander@2762
   355
dvander@2762
   356
  end_code = this_start_code;
dvander@2762
   357
  do
dvander@2762
   358
    {
dvander@2762
   359
    int back = GET(end_code, 2+LINK_SIZE);
dvander@2762
   360
    if (back > max_back) max_back = back;
dvander@2762
   361
    end_code += GET(end_code, 1);
dvander@2762
   362
    }
dvander@2762
   363
  while (*end_code == OP_ALT);
dvander@2762
   364
dvander@2762
   365
  /* If we can't go back the amount required for the longest lookbehind
dvander@2762
   366
  pattern, go back as far as we can; some alternatives may still be viable. */
dvander@2762
   367
dvander@2762
   368
#ifdef SUPPORT_UTF8
dvander@2762
   369
  /* In character mode we have to step back character by character */
dvander@2762
   370
dvander@2762
   371
  if (utf8)
dvander@2762
   372
    {
dvander@2762
   373
    for (gone_back = 0; gone_back < max_back; gone_back++)
dvander@2762
   374
      {
dvander@2762
   375
      if (current_subject <= start_subject) break;
dvander@2762
   376
      current_subject--;
dvander@2762
   377
      while (current_subject > start_subject &&
dvander@2762
   378
             (*current_subject & 0xc0) == 0x80)
dvander@2762
   379
        current_subject--;
dvander@2762
   380
      }
dvander@2762
   381
    }
dvander@2762
   382
  else
dvander@2762
   383
#endif
dvander@2762
   384
dvander@2762
   385
  /* In byte-mode we can do this quickly. */
dvander@2762
   386
dvander@2762
   387
    {
dvander@2762
   388
    gone_back = (current_subject - max_back < start_subject)?
dvander@2762
   389
      current_subject - start_subject : max_back;
dvander@2762
   390
    current_subject -= gone_back;
dvander@2762
   391
    }
dvander@2762
   392
dvander@2762
   393
  /* Now we can process the individual branches. */
dvander@2762
   394
dvander@2762
   395
  end_code = this_start_code;
dvander@2762
   396
  do
dvander@2762
   397
    {
dvander@2762
   398
    int back = GET(end_code, 2+LINK_SIZE);
dvander@2762
   399
    if (back <= gone_back)
dvander@2762
   400
      {
dvander@2762
   401
      int bstate = end_code - start_code + 2 + 2*LINK_SIZE;
dvander@2762
   402
      ADD_NEW_DATA(-bstate, 0, gone_back - back);
dvander@2762
   403
      }
dvander@2762
   404
    end_code += GET(end_code, 1);
dvander@2762
   405
    }
dvander@2762
   406
  while (*end_code == OP_ALT);
dvander@2762
   407
 }
dvander@2762
   408
dvander@2762
   409
/* This is the code for a "normal" subpattern (not a backward assertion). The
dvander@2762
   410
start of a whole pattern is always one of these. If we are at the top level,
dvander@2762
   411
we may be asked to restart matching from the same point that we reached for a
dvander@2762
   412
previous partial match. We still have to scan through the top-level branches to
dvander@2762
   413
find the end state. */
dvander@2762
   414
dvander@2762
   415
else
dvander@2762
   416
  {
dvander@2762
   417
  end_code = this_start_code;
dvander@2762
   418
dvander@2762
   419
  /* Restarting */
dvander@2762
   420
dvander@2762
   421
  if (rlevel == 1 && (md->moptions & PCRE_DFA_RESTART) != 0)
dvander@2762
   422
    {
dvander@2762
   423
    do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT);
dvander@2762
   424
    new_count = workspace[1];
dvander@2762
   425
    if (!workspace[0])
dvander@2762
   426
      memcpy(new_states, active_states, new_count * sizeof(stateblock));
dvander@2762
   427
    }
dvander@2762
   428
dvander@2762
   429
  /* Not restarting */
dvander@2762
   430
dvander@2762
   431
  else
dvander@2762
   432
    {
dvander@2762
   433
    int length = 1 + LINK_SIZE +
dvander@2762
   434
      ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA)? 2:0);
dvander@2762
   435
    do
dvander@2762
   436
      {
dvander@2762
   437
      ADD_NEW(end_code - start_code + length, 0);
dvander@2762
   438
      end_code += GET(end_code, 1);
dvander@2762
   439
      length = 1 + LINK_SIZE;
dvander@2762
   440
      }
dvander@2762
   441
    while (*end_code == OP_ALT);
dvander@2762
   442
    }
dvander@2762
   443
  }
dvander@2762
   444
dvander@2762
   445
workspace[0] = 0;    /* Bit indicating which vector is current */
dvander@2762
   446
dvander@2762
   447
DPRINTF(("%.*sEnd state = %d\n", rlevel*2-2, SP, end_code - start_code));
dvander@2762
   448
dvander@2762
   449
/* Loop for scanning the subject */
dvander@2762
   450
dvander@2762
   451
ptr = current_subject;
dvander@2762
   452
for (;;)
dvander@2762
   453
  {
dvander@2762
   454
  int i, j;
dvander@2762
   455
  int clen, dlen;
dvander@2762
   456
  unsigned int c, d;
dvander@2762
   457
dvander@2762
   458
  /* Make the new state list into the active state list and empty the
dvander@2762
   459
  new state list. */
dvander@2762
   460
dvander@2762
   461
  temp_states = active_states;
dvander@2762
   462
  active_states = new_states;
dvander@2762
   463
  new_states = temp_states;
dvander@2762
   464
  active_count = new_count;
dvander@2762
   465
  new_count = 0;
dvander@2762
   466
dvander@2762
   467
  workspace[0] ^= 1;              /* Remember for the restarting feature */
dvander@2762
   468
  workspace[1] = active_count;
dvander@2762
   469
dvander@2762
   470
#ifdef DEBUG
dvander@2762
   471
  printf("%.*sNext character: rest of subject = \"", rlevel*2-2, SP);
dvander@2762
   472
  pchars((uschar *)ptr, strlen((char *)ptr), stdout);
dvander@2762
   473
  printf("\"\n");
dvander@2762
   474
dvander@2762
   475
  printf("%.*sActive states: ", rlevel*2-2, SP);
dvander@2762
   476
  for (i = 0; i < active_count; i++)
dvander@2762
   477
    printf("%d/%d ", active_states[i].offset, active_states[i].count);
dvander@2762
   478
  printf("\n");
dvander@2762
   479
#endif
dvander@2762
   480
dvander@2762
   481
  /* Set the pointers for adding new states */
dvander@2762
   482
dvander@2762
   483
  next_active_state = active_states + active_count;
dvander@2762
   484
  next_new_state = new_states;
dvander@2762
   485
dvander@2762
   486
  /* Load the current character from the subject outside the loop, as many
dvander@2762
   487
  different states may want to look at it, and we assume that at least one
dvander@2762
   488
  will. */
dvander@2762
   489
dvander@2762
   490
  if (ptr < end_subject)
dvander@2762
   491
    {
dvander@2762
   492
    clen = 1;        /* Number of bytes in the character */
dvander@2762
   493
#ifdef SUPPORT_UTF8
dvander@2762
   494
    if (utf8) { GETCHARLEN(c, ptr, clen); } else
dvander@2762
   495
#endif  /* SUPPORT_UTF8 */
dvander@2762
   496
    c = *ptr;
dvander@2762
   497
    }
dvander@2762
   498
  else
dvander@2762
   499
    {
dvander@2762
   500
    clen = 0;        /* This indicates the end of the subject */
dvander@2762
   501
    c = NOTACHAR;    /* This value should never actually be used */
dvander@2762
   502
    }
dvander@2762
   503
dvander@2762
   504
  /* Scan up the active states and act on each one. The result of an action
dvander@2762
   505
  may be to add more states to the currently active list (e.g. on hitting a
dvander@2762
   506
  parenthesis) or it may be to put states on the new list, for considering
dvander@2762
   507
  when we move the character pointer on. */
dvander@2762
   508
dvander@2762
   509
  for (i = 0; i < active_count; i++)
dvander@2762
   510
    {
dvander@2762
   511
    stateblock *current_state = active_states + i;
dvander@2762
   512
    const uschar *code;
dvander@2762
   513
    int state_offset = current_state->offset;
dvander@2762
   514
    int count, codevalue, rrc;
dvander@2762
   515
dvander@2762
   516
#ifdef DEBUG
dvander@2762
   517
    printf ("%.*sProcessing state %d c=", rlevel*2-2, SP, state_offset);
dvander@2762
   518
    if (clen == 0) printf("EOL\n");
dvander@2762
   519
      else if (c > 32 && c < 127) printf("'%c'\n", c);
dvander@2762
   520
        else printf("0x%02x\n", c);
dvander@2762
   521
#endif
dvander@2762
   522
dvander@2762
   523
    /* This variable is referred to implicity in the ADD_xxx macros. */
dvander@2762
   524
dvander@2762
   525
    ims = current_state->ims;
dvander@2762
   526
dvander@2762
   527
    /* A negative offset is a special case meaning "hold off going to this
dvander@2762
   528
    (negated) state until the number of characters in the data field have
dvander@2762
   529
    been skipped". */
dvander@2762
   530
dvander@2762
   531
    if (state_offset < 0)
dvander@2762
   532
      {
dvander@2762
   533
      if (current_state->data > 0)
dvander@2762
   534
        {
dvander@2762
   535
        DPRINTF(("%.*sSkipping this character\n", rlevel*2-2, SP));
dvander@2762
   536
        ADD_NEW_DATA(state_offset, current_state->count,
dvander@2762
   537
          current_state->data - 1);
dvander@2762
   538
        continue;
dvander@2762
   539
        }
dvander@2762
   540
      else
dvander@2762
   541
        {
dvander@2762
   542
        current_state->offset = state_offset = -state_offset;
dvander@2762
   543
        }
dvander@2762
   544
      }
dvander@2762
   545
dvander@2762
   546
    /* Check for a duplicate state with the same count, and skip if found. */
dvander@2762
   547
dvander@2762
   548
    for (j = 0; j < i; j++)
dvander@2762
   549
      {
dvander@2762
   550
      if (active_states[j].offset == state_offset &&
dvander@2762
   551
          active_states[j].count == current_state->count)
dvander@2762
   552
        {
dvander@2762
   553
        DPRINTF(("%.*sDuplicate state: skipped\n", rlevel*2-2, SP));
dvander@2762
   554
        goto NEXT_ACTIVE_STATE;
dvander@2762
   555
        }
dvander@2762
   556
      }
dvander@2762
   557
dvander@2762
   558
    /* The state offset is the offset to the opcode */
dvander@2762
   559
dvander@2762
   560
    code = start_code + state_offset;
dvander@2762
   561
    codevalue = *code;
dvander@2762
   562
dvander@2762
   563
    /* If this opcode is followed by an inline character, load it. It is
dvander@2762
   564
    tempting to test for the presence of a subject character here, but that
dvander@2762
   565
    is wrong, because sometimes zero repetitions of the subject are
dvander@2762
   566
    permitted.
dvander@2762
   567
dvander@2762
   568
    We also use this mechanism for opcodes such as OP_TYPEPLUS that take an
dvander@2762
   569
    argument that is not a data character - but is always one byte long. We
dvander@2762
   570
    have to take special action to deal with  \P, \p, \H, \h, \V, \v and \X in
dvander@2762
   571
    this case. To keep the other cases fast, convert these ones to new opcodes.
dvander@2762
   572
    */
dvander@2762
   573
dvander@2762
   574
    if (coptable[codevalue] > 0)
dvander@2762
   575
      {
dvander@2762
   576
      dlen = 1;
dvander@2762
   577
#ifdef SUPPORT_UTF8
dvander@2762
   578
      if (utf8) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else
dvander@2762
   579
#endif  /* SUPPORT_UTF8 */
dvander@2762
   580
      d = code[coptable[codevalue]];
dvander@2762
   581
      if (codevalue >= OP_TYPESTAR)
dvander@2762
   582
        {
dvander@2762
   583
        switch(d)
dvander@2762
   584
          {
dvander@2762
   585
          case OP_ANYBYTE: return PCRE_ERROR_DFA_UITEM;
dvander@2762
   586
          case OP_NOTPROP:
dvander@2762
   587
          case OP_PROP: codevalue += OP_PROP_EXTRA; break;
dvander@2762
   588
          case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break;
dvander@2762
   589
          case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break;
dvander@2762
   590
          case OP_NOT_HSPACE:
dvander@2762
   591
          case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break;
dvander@2762
   592
          case OP_NOT_VSPACE:
dvander@2762
   593
          case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break;
dvander@2762
   594
          default: break;
dvander@2762
   595
          }
dvander@2762
   596
        }
dvander@2762
   597
      }
dvander@2762
   598
    else
dvander@2762
   599
      {
dvander@2762
   600
      dlen = 0;         /* Not strictly necessary, but compilers moan */
dvander@2762
   601
      d = NOTACHAR;     /* if these variables are not set. */
dvander@2762
   602
      }
dvander@2762
   603
dvander@2762
   604
dvander@2762
   605
    /* Now process the individual opcodes */
dvander@2762
   606
dvander@2762
   607
    switch (codevalue)
dvander@2762
   608
      {
dvander@2762
   609
dvander@2762
   610
/* ========================================================================== */
dvander@2762
   611
      /* Reached a closing bracket. If not at the end of the pattern, carry
dvander@2762
   612
      on with the next opcode. Otherwise, unless we have an empty string and
dvander@2762
   613
      PCRE_NOTEMPTY is set, save the match data, shifting up all previous
dvander@2762
   614
      matches so we always have the longest first. */
dvander@2762
   615
dvander@2762
   616
      case OP_KET:
dvander@2762
   617
      case OP_KETRMIN:
dvander@2762
   618
      case OP_KETRMAX:
dvander@2762
   619
      if (code != end_code)
dvander@2762
   620
        {
dvander@2762
   621
        ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0);
dvander@2762
   622
        if (codevalue != OP_KET)
dvander@2762
   623
          {
dvander@2762
   624
          ADD_ACTIVE(state_offset - GET(code, 1), 0);
dvander@2762
   625
          }
dvander@2762
   626
        }
dvander@2762
   627
      else if (ptr > current_subject || (md->moptions & PCRE_NOTEMPTY) == 0)
dvander@2762
   628
        {
dvander@2762
   629
        if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0;
dvander@2762
   630
          else if (match_count > 0 && ++match_count * 2 >= offsetcount)
dvander@2762
   631
            match_count = 0;
dvander@2762
   632
        count = ((match_count == 0)? offsetcount : match_count * 2) - 2;
dvander@2762
   633
        if (count > 0) memmove(offsets + 2, offsets, count * sizeof(int));
dvander@2762
   634
        if (offsetcount >= 2)
dvander@2762
   635
          {
dvander@2762
   636
          offsets[0] = current_subject - start_subject;
dvander@2762
   637
          offsets[1] = ptr - start_subject;
dvander@2762
   638
          DPRINTF(("%.*sSet matched string = \"%.*s\"\n", rlevel*2-2, SP,
dvander@2762
   639
            offsets[1] - offsets[0], current_subject));
dvander@2762
   640
          }
dvander@2762
   641
        if ((md->moptions & PCRE_DFA_SHORTEST) != 0)
dvander@2762
   642
          {
dvander@2762
   643
          DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n"
dvander@2762
   644
            "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel,
dvander@2762
   645
            match_count, rlevel*2-2, SP));
dvander@2762
   646
          return match_count;
dvander@2762
   647
          }
dvander@2762
   648
        }
dvander@2762
   649
      break;
dvander@2762
   650
dvander@2762
   651
/* ========================================================================== */
dvander@2762
   652
      /* These opcodes add to the current list of states without looking
dvander@2762
   653
      at the current character. */
dvander@2762
   654
dvander@2762
   655
      /*-----------------------------------------------------------------*/
dvander@2762
   656
      case OP_ALT:
dvander@2762
   657
      do { code += GET(code, 1); } while (*code == OP_ALT);
dvander@2762
   658
      ADD_ACTIVE(code - start_code, 0);
dvander@2762
   659
      break;
dvander@2762
   660
dvander@2762
   661
      /*-----------------------------------------------------------------*/
dvander@2762
   662
      case OP_BRA:
dvander@2762
   663
      case OP_SBRA:
dvander@2762
   664
      do
dvander@2762
   665
        {
dvander@2762
   666
        ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0);
dvander@2762
   667
        code += GET(code, 1);
dvander@2762
   668
        }
dvander@2762
   669
      while (*code == OP_ALT);
dvander@2762
   670
      break;
dvander@2762
   671
dvander@2762
   672
      /*-----------------------------------------------------------------*/
dvander@2762
   673
      case OP_CBRA:
dvander@2762
   674
      case OP_SCBRA:
dvander@2762
   675
      ADD_ACTIVE(code - start_code + 3 + LINK_SIZE,  0);
dvander@2762
   676
      code += GET(code, 1);
dvander@2762
   677
      while (*code == OP_ALT)
dvander@2762
   678
        {
dvander@2762
   679
        ADD_ACTIVE(code - start_code + 1 + LINK_SIZE,  0);
dvander@2762
   680
        code += GET(code, 1);
dvander@2762
   681
        }
dvander@2762
   682
      break;
dvander@2762
   683
dvander@2762
   684
      /*-----------------------------------------------------------------*/
dvander@2762
   685
      case OP_BRAZERO:
dvander@2762
   686
      case OP_BRAMINZERO:
dvander@2762
   687
      ADD_ACTIVE(state_offset + 1, 0);
dvander@2762
   688
      code += 1 + GET(code, 2);
dvander@2762
   689
      while (*code == OP_ALT) code += GET(code, 1);
dvander@2762
   690
      ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0);
dvander@2762
   691
      break;
dvander@2762
   692
dvander@2762
   693
      /*-----------------------------------------------------------------*/
dvander@2762
   694
      case OP_SKIPZERO:
dvander@2762
   695
      code += 1 + GET(code, 2);
dvander@2762
   696
      while (*code == OP_ALT) code += GET(code, 1);
dvander@2762
   697
      ADD_ACTIVE(code - start_code + 1 + LINK_SIZE, 0);
dvander@2762
   698
      break;
dvander@2762
   699
dvander@2762
   700
      /*-----------------------------------------------------------------*/
dvander@2762
   701
      case OP_CIRC:
dvander@2762
   702
      if ((ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0) ||
dvander@2762
   703
          ((ims & PCRE_MULTILINE) != 0 &&
dvander@2762
   704
            ptr != end_subject &&
dvander@2762
   705
            WAS_NEWLINE(ptr)))
dvander@2762
   706
        { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   707
      break;
dvander@2762
   708
dvander@2762
   709
      /*-----------------------------------------------------------------*/
dvander@2762
   710
      case OP_EOD:
dvander@2762
   711
      if (ptr >= end_subject) { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   712
      break;
dvander@2762
   713
dvander@2762
   714
      /*-----------------------------------------------------------------*/
dvander@2762
   715
      case OP_OPT:
dvander@2762
   716
      ims = code[1];
dvander@2762
   717
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
   718
      break;
dvander@2762
   719
dvander@2762
   720
      /*-----------------------------------------------------------------*/
dvander@2762
   721
      case OP_SOD:
dvander@2762
   722
      if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   723
      break;
dvander@2762
   724
dvander@2762
   725
      /*-----------------------------------------------------------------*/
dvander@2762
   726
      case OP_SOM:
dvander@2762
   727
      if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   728
      break;
dvander@2762
   729
dvander@2762
   730
dvander@2762
   731
/* ========================================================================== */
dvander@2762
   732
      /* These opcodes inspect the next subject character, and sometimes
dvander@2762
   733
      the previous one as well, but do not have an argument. The variable
dvander@2762
   734
      clen contains the length of the current character and is zero if we are
dvander@2762
   735
      at the end of the subject. */
dvander@2762
   736
dvander@2762
   737
      /*-----------------------------------------------------------------*/
dvander@2762
   738
      case OP_ANY:
dvander@2762
   739
      if (clen > 0 && !IS_NEWLINE(ptr))
dvander@2762
   740
        { ADD_NEW(state_offset + 1, 0); }
dvander@2762
   741
      break;
dvander@2762
   742
dvander@2762
   743
      /*-----------------------------------------------------------------*/
dvander@2762
   744
      case OP_ALLANY:
dvander@2762
   745
      if (clen > 0)
dvander@2762
   746
        { ADD_NEW(state_offset + 1, 0); }
dvander@2762
   747
      break;
dvander@2762
   748
dvander@2762
   749
      /*-----------------------------------------------------------------*/
dvander@2762
   750
      case OP_EODN:
dvander@2762
   751
      if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - md->nllen))
dvander@2762
   752
        { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   753
      break;
dvander@2762
   754
dvander@2762
   755
      /*-----------------------------------------------------------------*/
dvander@2762
   756
      case OP_DOLL:
dvander@2762
   757
      if ((md->moptions & PCRE_NOTEOL) == 0)
dvander@2762
   758
        {
dvander@2762
   759
        if (clen == 0 ||
dvander@2762
   760
            ((md->poptions & PCRE_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) &&
dvander@2762
   761
               ((ims & PCRE_MULTILINE) != 0 || ptr == end_subject - md->nllen)
dvander@2762
   762
            ))
dvander@2762
   763
          { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   764
        }
dvander@2762
   765
      else if ((ims & PCRE_MULTILINE) != 0 && IS_NEWLINE(ptr))
dvander@2762
   766
        { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   767
      break;
dvander@2762
   768
dvander@2762
   769
      /*-----------------------------------------------------------------*/
dvander@2762
   770
dvander@2762
   771
      case OP_DIGIT:
dvander@2762
   772
      case OP_WHITESPACE:
dvander@2762
   773
      case OP_WORDCHAR:
dvander@2762
   774
      if (clen > 0 && c < 256 &&
dvander@2762
   775
            ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)
dvander@2762
   776
        { ADD_NEW(state_offset + 1, 0); }
dvander@2762
   777
      break;
dvander@2762
   778
dvander@2762
   779
      /*-----------------------------------------------------------------*/
dvander@2762
   780
      case OP_NOT_DIGIT:
dvander@2762
   781
      case OP_NOT_WHITESPACE:
dvander@2762
   782
      case OP_NOT_WORDCHAR:
dvander@2762
   783
      if (clen > 0 && (c >= 256 ||
dvander@2762
   784
            ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0))
dvander@2762
   785
        { ADD_NEW(state_offset + 1, 0); }
dvander@2762
   786
      break;
dvander@2762
   787
dvander@2762
   788
      /*-----------------------------------------------------------------*/
dvander@2762
   789
      case OP_WORD_BOUNDARY:
dvander@2762
   790
      case OP_NOT_WORD_BOUNDARY:
dvander@2762
   791
        {
dvander@2762
   792
        int left_word, right_word;
dvander@2762
   793
dvander@2762
   794
        if (ptr > start_subject)
dvander@2762
   795
          {
dvander@2762
   796
          const uschar *temp = ptr - 1;
dvander@2762
   797
#ifdef SUPPORT_UTF8
dvander@2762
   798
          if (utf8) BACKCHAR(temp);
dvander@2762
   799
#endif
dvander@2762
   800
          GETCHARTEST(d, temp);
dvander@2762
   801
          left_word = d < 256 && (ctypes[d] & ctype_word) != 0;
dvander@2762
   802
          }
dvander@2762
   803
        else left_word = 0;
dvander@2762
   804
dvander@2762
   805
        if (clen > 0) right_word = c < 256 && (ctypes[c] & ctype_word) != 0;
dvander@2762
   806
          else right_word = 0;
dvander@2762
   807
dvander@2762
   808
        if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY))
dvander@2762
   809
          { ADD_ACTIVE(state_offset + 1, 0); }
dvander@2762
   810
        }
dvander@2762
   811
      break;
dvander@2762
   812
dvander@2762
   813
dvander@2762
   814
      /*-----------------------------------------------------------------*/
dvander@2762
   815
      /* Check the next character by Unicode property. We will get here only
dvander@2762
   816
      if the support is in the binary; otherwise a compile-time error occurs.
dvander@2762
   817
      */
dvander@2762
   818
dvander@2762
   819
#ifdef SUPPORT_UCP
dvander@2762
   820
      case OP_PROP:
dvander@2762
   821
      case OP_NOTPROP:
dvander@2762
   822
      if (clen > 0)
dvander@2762
   823
        {
dvander@2762
   824
        BOOL OK;
dvander@2762
   825
        const ucd_record * prop = GET_UCD(c);
dvander@2762
   826
        switch(code[1])
dvander@2762
   827
          {
dvander@2762
   828
          case PT_ANY:
dvander@2762
   829
          OK = TRUE;
dvander@2762
   830
          break;
dvander@2762
   831
dvander@2762
   832
          case PT_LAMP:
dvander@2762
   833
          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt;
dvander@2762
   834
          break;
dvander@2762
   835
dvander@2762
   836
          case PT_GC:
dvander@2762
   837
          OK = _pcre_ucp_gentype[prop->chartype] == code[2];
dvander@2762
   838
          break;
dvander@2762
   839
dvander@2762
   840
          case PT_PC:
dvander@2762
   841
          OK = prop->chartype == code[2];
dvander@2762
   842
          break;
dvander@2762
   843
dvander@2762
   844
          case PT_SC:
dvander@2762
   845
          OK = prop->script == code[2];
dvander@2762
   846
          break;
dvander@2762
   847
dvander@2762
   848
          /* Should never occur, but keep compilers from grumbling. */
dvander@2762
   849
dvander@2762
   850
          default:
dvander@2762
   851
          OK = codevalue != OP_PROP;
dvander@2762
   852
          break;
dvander@2762
   853
          }
dvander@2762
   854
dvander@2762
   855
        if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); }
dvander@2762
   856
        }
dvander@2762
   857
      break;
dvander@2762
   858
#endif
dvander@2762
   859
dvander@2762
   860
dvander@2762
   861
dvander@2762
   862
/* ========================================================================== */
dvander@2762
   863
      /* These opcodes likewise inspect the subject character, but have an
dvander@2762
   864
      argument that is not a data character. It is one of these opcodes:
dvander@2762
   865
      OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE,
dvander@2762
   866
      OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */
dvander@2762
   867
dvander@2762
   868
      case OP_TYPEPLUS:
dvander@2762
   869
      case OP_TYPEMINPLUS:
dvander@2762
   870
      case OP_TYPEPOSPLUS:
dvander@2762
   871
      count = current_state->count;  /* Already matched */
dvander@2762
   872
      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
dvander@2762
   873
      if (clen > 0)
dvander@2762
   874
        {
dvander@2762
   875
        if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
dvander@2762
   876
            (c < 256 &&
dvander@2762
   877
              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
dvander@2762
   878
              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
dvander@2762
   879
          {
dvander@2762
   880
          if (count > 0 && codevalue == OP_TYPEPOSPLUS)
dvander@2762
   881
            {
dvander@2762
   882
            active_count--;            /* Remove non-match possibility */
dvander@2762
   883
            next_active_state--;
dvander@2762
   884
            }
dvander@2762
   885
          count++;
dvander@2762
   886
          ADD_NEW(state_offset, count);
dvander@2762
   887
          }
dvander@2762
   888
        }
dvander@2762
   889
      break;
dvander@2762
   890
dvander@2762
   891
      /*-----------------------------------------------------------------*/
dvander@2762
   892
      case OP_TYPEQUERY:
dvander@2762
   893
      case OP_TYPEMINQUERY:
dvander@2762
   894
      case OP_TYPEPOSQUERY:
dvander@2762
   895
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
   896
      if (clen > 0)
dvander@2762
   897
        {
dvander@2762
   898
        if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
dvander@2762
   899
            (c < 256 &&
dvander@2762
   900
              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
dvander@2762
   901
              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
dvander@2762
   902
          {
dvander@2762
   903
          if (codevalue == OP_TYPEPOSQUERY)
dvander@2762
   904
            {
dvander@2762
   905
            active_count--;            /* Remove non-match possibility */
dvander@2762
   906
            next_active_state--;
dvander@2762
   907
            }
dvander@2762
   908
          ADD_NEW(state_offset + 2, 0);
dvander@2762
   909
          }
dvander@2762
   910
        }
dvander@2762
   911
      break;
dvander@2762
   912
dvander@2762
   913
      /*-----------------------------------------------------------------*/
dvander@2762
   914
      case OP_TYPESTAR:
dvander@2762
   915
      case OP_TYPEMINSTAR:
dvander@2762
   916
      case OP_TYPEPOSSTAR:
dvander@2762
   917
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
   918
      if (clen > 0)
dvander@2762
   919
        {
dvander@2762
   920
        if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
dvander@2762
   921
            (c < 256 &&
dvander@2762
   922
              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
dvander@2762
   923
              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
dvander@2762
   924
          {
dvander@2762
   925
          if (codevalue == OP_TYPEPOSSTAR)
dvander@2762
   926
            {
dvander@2762
   927
            active_count--;            /* Remove non-match possibility */
dvander@2762
   928
            next_active_state--;
dvander@2762
   929
            }
dvander@2762
   930
          ADD_NEW(state_offset, 0);
dvander@2762
   931
          }
dvander@2762
   932
        }
dvander@2762
   933
      break;
dvander@2762
   934
dvander@2762
   935
      /*-----------------------------------------------------------------*/
dvander@2762
   936
      case OP_TYPEEXACT:
dvander@2762
   937
      count = current_state->count;  /* Number already matched */
dvander@2762
   938
      if (clen > 0)
dvander@2762
   939
        {
dvander@2762
   940
        if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
dvander@2762
   941
            (c < 256 &&
dvander@2762
   942
              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
dvander@2762
   943
              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
dvander@2762
   944
          {
dvander@2762
   945
          if (++count >= GET2(code, 1))
dvander@2762
   946
            { ADD_NEW(state_offset + 4, 0); }
dvander@2762
   947
          else
dvander@2762
   948
            { ADD_NEW(state_offset, count); }
dvander@2762
   949
          }
dvander@2762
   950
        }
dvander@2762
   951
      break;
dvander@2762
   952
dvander@2762
   953
      /*-----------------------------------------------------------------*/
dvander@2762
   954
      case OP_TYPEUPTO:
dvander@2762
   955
      case OP_TYPEMINUPTO:
dvander@2762
   956
      case OP_TYPEPOSUPTO:
dvander@2762
   957
      ADD_ACTIVE(state_offset + 4, 0);
dvander@2762
   958
      count = current_state->count;  /* Number already matched */
dvander@2762
   959
      if (clen > 0)
dvander@2762
   960
        {
dvander@2762
   961
        if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
dvander@2762
   962
            (c < 256 &&
dvander@2762
   963
              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
dvander@2762
   964
              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
dvander@2762
   965
          {
dvander@2762
   966
          if (codevalue == OP_TYPEPOSUPTO)
dvander@2762
   967
            {
dvander@2762
   968
            active_count--;           /* Remove non-match possibility */
dvander@2762
   969
            next_active_state--;
dvander@2762
   970
            }
dvander@2762
   971
          if (++count >= GET2(code, 1))
dvander@2762
   972
            { ADD_NEW(state_offset + 4, 0); }
dvander@2762
   973
          else
dvander@2762
   974
            { ADD_NEW(state_offset, count); }
dvander@2762
   975
          }
dvander@2762
   976
        }
dvander@2762
   977
      break;
dvander@2762
   978
dvander@2762
   979
/* ========================================================================== */
dvander@2762
   980
      /* These are virtual opcodes that are used when something like
dvander@2762
   981
      OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its
dvander@2762
   982
      argument. It keeps the code above fast for the other cases. The argument
dvander@2762
   983
      is in the d variable. */
dvander@2762
   984
dvander@2762
   985
#ifdef SUPPORT_UCP
dvander@2762
   986
      case OP_PROP_EXTRA + OP_TYPEPLUS:
dvander@2762
   987
      case OP_PROP_EXTRA + OP_TYPEMINPLUS:
dvander@2762
   988
      case OP_PROP_EXTRA + OP_TYPEPOSPLUS:
dvander@2762
   989
      count = current_state->count;           /* Already matched */
dvander@2762
   990
      if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); }
dvander@2762
   991
      if (clen > 0)
dvander@2762
   992
        {
dvander@2762
   993
        BOOL OK;
dvander@2762
   994
        const ucd_record * prop = GET_UCD(c);
dvander@2762
   995
        switch(code[2])
dvander@2762
   996
          {
dvander@2762
   997
          case PT_ANY:
dvander@2762
   998
          OK = TRUE;
dvander@2762
   999
          break;
dvander@2762
  1000
dvander@2762
  1001
          case PT_LAMP:
dvander@2762
  1002
          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt;
dvander@2762
  1003
          break;
dvander@2762
  1004
dvander@2762
  1005
          case PT_GC:
dvander@2762
  1006
          OK = _pcre_ucp_gentype[prop->chartype] == code[3];
dvander@2762
  1007
          break;
dvander@2762
  1008
dvander@2762
  1009
          case PT_PC:
dvander@2762
  1010
          OK = prop->chartype == code[3];
dvander@2762
  1011
          break;
dvander@2762
  1012
dvander@2762
  1013
          case PT_SC:
dvander@2762
  1014
          OK = prop->script == code[3];
dvander@2762
  1015
          break;
dvander@2762
  1016
dvander@2762
  1017
          /* Should never occur, but keep compilers from grumbling. */
dvander@2762
  1018
dvander@2762
  1019
          default:
dvander@2762
  1020
          OK = codevalue != OP_PROP;
dvander@2762
  1021
          break;
dvander@2762
  1022
          }
dvander@2762
  1023
dvander@2762
  1024
        if (OK == (d == OP_PROP))
dvander@2762
  1025
          {
dvander@2762
  1026
          if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS)
dvander@2762
  1027
            {
dvander@2762
  1028
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1029
            next_active_state--;
dvander@2762
  1030
            }
dvander@2762
  1031
          count++;
dvander@2762
  1032
          ADD_NEW(state_offset, count);
dvander@2762
  1033
          }
dvander@2762
  1034
        }
dvander@2762
  1035
      break;
dvander@2762
  1036
dvander@2762
  1037
      /*-----------------------------------------------------------------*/
dvander@2762
  1038
      case OP_EXTUNI_EXTRA + OP_TYPEPLUS:
dvander@2762
  1039
      case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS:
dvander@2762
  1040
      case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS:
dvander@2762
  1041
      count = current_state->count;  /* Already matched */
dvander@2762
  1042
      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
dvander@2762
  1043
      if (clen > 0 && UCD_CATEGORY(c) != ucp_M)
dvander@2762
  1044
        {
dvander@2762
  1045
        const uschar *nptr = ptr + clen;
dvander@2762
  1046
        int ncount = 0;
dvander@2762
  1047
        if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS)
dvander@2762
  1048
          {
dvander@2762
  1049
          active_count--;           /* Remove non-match possibility */
dvander@2762
  1050
          next_active_state--;
dvander@2762
  1051
          }
dvander@2762
  1052
        while (nptr < end_subject)
dvander@2762
  1053
          {
dvander@2762
  1054
          int nd;
dvander@2762
  1055
          int ndlen = 1;
dvander@2762
  1056
          GETCHARLEN(nd, nptr, ndlen);
dvander@2762
  1057
          if (UCD_CATEGORY(nd) != ucp_M) break;
dvander@2762
  1058
          ncount++;
dvander@2762
  1059
          nptr += ndlen;
dvander@2762
  1060
          }
dvander@2762
  1061
        count++;
dvander@2762
  1062
        ADD_NEW_DATA(-state_offset, count, ncount);
dvander@2762
  1063
        }
dvander@2762
  1064
      break;
dvander@2762
  1065
#endif
dvander@2762
  1066
dvander@2762
  1067
      /*-----------------------------------------------------------------*/
dvander@2762
  1068
      case OP_ANYNL_EXTRA + OP_TYPEPLUS:
dvander@2762
  1069
      case OP_ANYNL_EXTRA + OP_TYPEMINPLUS:
dvander@2762
  1070
      case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS:
dvander@2762
  1071
      count = current_state->count;  /* Already matched */
dvander@2762
  1072
      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
dvander@2762
  1073
      if (clen > 0)
dvander@2762
  1074
        {
dvander@2762
  1075
        int ncount = 0;
dvander@2762
  1076
        switch (c)
dvander@2762
  1077
          {
dvander@2762
  1078
          case 0x000b:
dvander@2762
  1079
          case 0x000c:
dvander@2762
  1080
          case 0x0085:
dvander@2762
  1081
          case 0x2028:
dvander@2762
  1082
          case 0x2029:
dvander@2762
  1083
          if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
dvander@2762
  1084
          goto ANYNL01;
dvander@2762
  1085
dvander@2762
  1086
          case 0x000d:
dvander@2762
  1087
          if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1;
dvander@2762
  1088
          /* Fall through */
dvander@2762
  1089
dvander@2762
  1090
          ANYNL01:
dvander@2762
  1091
          case 0x000a:
dvander@2762
  1092
          if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS)
dvander@2762
  1093
            {
dvander@2762
  1094
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1095
            next_active_state--;
dvander@2762
  1096
            }
dvander@2762
  1097
          count++;
dvander@2762
  1098
          ADD_NEW_DATA(-state_offset, count, ncount);
dvander@2762
  1099
          break;
dvander@2762
  1100
dvander@2762
  1101
          default:
dvander@2762
  1102
          break;
dvander@2762
  1103
          }
dvander@2762
  1104
        }
dvander@2762
  1105
      break;
dvander@2762
  1106
dvander@2762
  1107
      /*-----------------------------------------------------------------*/
dvander@2762
  1108
      case OP_VSPACE_EXTRA + OP_TYPEPLUS:
dvander@2762
  1109
      case OP_VSPACE_EXTRA + OP_TYPEMINPLUS:
dvander@2762
  1110
      case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS:
dvander@2762
  1111
      count = current_state->count;  /* Already matched */
dvander@2762
  1112
      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
dvander@2762
  1113
      if (clen > 0)
dvander@2762
  1114
        {
dvander@2762
  1115
        BOOL OK;
dvander@2762
  1116
        switch (c)
dvander@2762
  1117
          {
dvander@2762
  1118
          case 0x000a:
dvander@2762
  1119
          case 0x000b:
dvander@2762
  1120
          case 0x000c:
dvander@2762
  1121
          case 0x000d:
dvander@2762
  1122
          case 0x0085:
dvander@2762
  1123
          case 0x2028:
dvander@2762
  1124
          case 0x2029:
dvander@2762
  1125
          OK = TRUE;
dvander@2762
  1126
          break;
dvander@2762
  1127
dvander@2762
  1128
          default:
dvander@2762
  1129
          OK = FALSE;
dvander@2762
  1130
          break;
dvander@2762
  1131
          }
dvander@2762
  1132
dvander@2762
  1133
        if (OK == (d == OP_VSPACE))
dvander@2762
  1134
          {
dvander@2762
  1135
          if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS)
dvander@2762
  1136
            {
dvander@2762
  1137
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1138
            next_active_state--;
dvander@2762
  1139
            }
dvander@2762
  1140
          count++;
dvander@2762
  1141
          ADD_NEW_DATA(-state_offset, count, 0);
dvander@2762
  1142
          }
dvander@2762
  1143
        }
dvander@2762
  1144
      break;
dvander@2762
  1145
dvander@2762
  1146
      /*-----------------------------------------------------------------*/
dvander@2762
  1147
      case OP_HSPACE_EXTRA + OP_TYPEPLUS:
dvander@2762
  1148
      case OP_HSPACE_EXTRA + OP_TYPEMINPLUS:
dvander@2762
  1149
      case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS:
dvander@2762
  1150
      count = current_state->count;  /* Already matched */
dvander@2762
  1151
      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
dvander@2762
  1152
      if (clen > 0)
dvander@2762
  1153
        {
dvander@2762
  1154
        BOOL OK;
dvander@2762
  1155
        switch (c)
dvander@2762
  1156
          {
dvander@2762
  1157
          case 0x09:      /* HT */
dvander@2762
  1158
          case 0x20:      /* SPACE */
dvander@2762
  1159
          case 0xa0:      /* NBSP */
dvander@2762
  1160
          case 0x1680:    /* OGHAM SPACE MARK */
dvander@2762
  1161
          case 0x180e:    /* MONGOLIAN VOWEL SEPARATOR */
dvander@2762
  1162
          case 0x2000:    /* EN QUAD */
dvander@2762
  1163
          case 0x2001:    /* EM QUAD */
dvander@2762
  1164
          case 0x2002:    /* EN SPACE */
dvander@2762
  1165
          case 0x2003:    /* EM SPACE */
dvander@2762
  1166
          case 0x2004:    /* THREE-PER-EM SPACE */
dvander@2762
  1167
          case 0x2005:    /* FOUR-PER-EM SPACE */
dvander@2762
  1168
          case 0x2006:    /* SIX-PER-EM SPACE */
dvander@2762
  1169
          case 0x2007:    /* FIGURE SPACE */
dvander@2762
  1170
          case 0x2008:    /* PUNCTUATION SPACE */
dvander@2762
  1171
          case 0x2009:    /* THIN SPACE */
dvander@2762
  1172
          case 0x200A:    /* HAIR SPACE */
dvander@2762
  1173
          case 0x202f:    /* NARROW NO-BREAK SPACE */
dvander@2762
  1174
          case 0x205f:    /* MEDIUM MATHEMATICAL SPACE */
dvander@2762
  1175
          case 0x3000:    /* IDEOGRAPHIC SPACE */
dvander@2762
  1176
          OK = TRUE;
dvander@2762
  1177
          break;
dvander@2762
  1178
dvander@2762
  1179
          default:
dvander@2762
  1180
          OK = FALSE;
dvander@2762
  1181
          break;
dvander@2762
  1182
          }
dvander@2762
  1183
dvander@2762
  1184
        if (OK == (d == OP_HSPACE))
dvander@2762
  1185
          {
dvander@2762
  1186
          if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS)
dvander@2762
  1187
            {
dvander@2762
  1188
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1189
            next_active_state--;
dvander@2762
  1190
            }
dvander@2762
  1191
          count++;
dvander@2762
  1192
          ADD_NEW_DATA(-state_offset, count, 0);
dvander@2762
  1193
          }
dvander@2762
  1194
        }
dvander@2762
  1195
      break;
dvander@2762
  1196
dvander@2762
  1197
      /*-----------------------------------------------------------------*/
dvander@2762
  1198
#ifdef SUPPORT_UCP
dvander@2762
  1199
      case OP_PROP_EXTRA + OP_TYPEQUERY:
dvander@2762
  1200
      case OP_PROP_EXTRA + OP_TYPEMINQUERY:
dvander@2762
  1201
      case OP_PROP_EXTRA + OP_TYPEPOSQUERY:
dvander@2762
  1202
      count = 4;
dvander@2762
  1203
      goto QS1;
dvander@2762
  1204
dvander@2762
  1205
      case OP_PROP_EXTRA + OP_TYPESTAR:
dvander@2762
  1206
      case OP_PROP_EXTRA + OP_TYPEMINSTAR:
dvander@2762
  1207
      case OP_PROP_EXTRA + OP_TYPEPOSSTAR:
dvander@2762
  1208
      count = 0;
dvander@2762
  1209
dvander@2762
  1210
      QS1:
dvander@2762
  1211
dvander@2762
  1212
      ADD_ACTIVE(state_offset + 4, 0);
dvander@2762
  1213
      if (clen > 0)
dvander@2762
  1214
        {
dvander@2762
  1215
        BOOL OK;
dvander@2762
  1216
        const ucd_record * prop = GET_UCD(c);
dvander@2762
  1217
        switch(code[2])
dvander@2762
  1218
          {
dvander@2762
  1219
          case PT_ANY:
dvander@2762
  1220
          OK = TRUE;
dvander@2762
  1221
          break;
dvander@2762
  1222
dvander@2762
  1223
          case PT_LAMP:
dvander@2762
  1224
          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt;
dvander@2762
  1225
          break;
dvander@2762
  1226
dvander@2762
  1227
          case PT_GC:
dvander@2762
  1228
          OK = _pcre_ucp_gentype[prop->chartype] == code[3];
dvander@2762
  1229
          break;
dvander@2762
  1230
dvander@2762
  1231
          case PT_PC:
dvander@2762
  1232
          OK = prop->chartype == code[3];
dvander@2762
  1233
          break;
dvander@2762
  1234
dvander@2762
  1235
          case PT_SC:
dvander@2762
  1236
          OK = prop->script == code[3];
dvander@2762
  1237
          break;
dvander@2762
  1238
dvander@2762
  1239
          /* Should never occur, but keep compilers from grumbling. */
dvander@2762
  1240
dvander@2762
  1241
          default:
dvander@2762
  1242
          OK = codevalue != OP_PROP;
dvander@2762
  1243
          break;
dvander@2762
  1244
          }
dvander@2762
  1245
dvander@2762
  1246
        if (OK == (d == OP_PROP))
dvander@2762
  1247
          {
dvander@2762
  1248
          if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR ||
dvander@2762
  1249
              codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY)
dvander@2762
  1250
            {
dvander@2762
  1251
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1252
            next_active_state--;
dvander@2762
  1253
            }
dvander@2762
  1254
          ADD_NEW(state_offset + count, 0);
dvander@2762
  1255
          }
dvander@2762
  1256
        }
dvander@2762
  1257
      break;
dvander@2762
  1258
dvander@2762
  1259
      /*-----------------------------------------------------------------*/
dvander@2762
  1260
      case OP_EXTUNI_EXTRA + OP_TYPEQUERY:
dvander@2762
  1261
      case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY:
dvander@2762
  1262
      case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY:
dvander@2762
  1263
      count = 2;
dvander@2762
  1264
      goto QS2;
dvander@2762
  1265
dvander@2762
  1266
      case OP_EXTUNI_EXTRA + OP_TYPESTAR:
dvander@2762
  1267
      case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR:
dvander@2762
  1268
      case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR:
dvander@2762
  1269
      count = 0;
dvander@2762
  1270
dvander@2762
  1271
      QS2:
dvander@2762
  1272
dvander@2762
  1273
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
  1274
      if (clen > 0 && UCD_CATEGORY(c) != ucp_M)
dvander@2762
  1275
        {
dvander@2762
  1276
        const uschar *nptr = ptr + clen;
dvander@2762
  1277
        int ncount = 0;
dvander@2762
  1278
        if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR ||
dvander@2762
  1279
            codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY)
dvander@2762
  1280
          {
dvander@2762
  1281
          active_count--;           /* Remove non-match possibility */
dvander@2762
  1282
          next_active_state--;
dvander@2762
  1283
          }
dvander@2762
  1284
        while (nptr < end_subject)
dvander@2762
  1285
          {
dvander@2762
  1286
          int nd;
dvander@2762
  1287
          int ndlen = 1;
dvander@2762
  1288
          GETCHARLEN(nd, nptr, ndlen);
dvander@2762
  1289
          if (UCD_CATEGORY(nd) != ucp_M) break;
dvander@2762
  1290
          ncount++;
dvander@2762
  1291
          nptr += ndlen;
dvander@2762
  1292
          }
dvander@2762
  1293
        ADD_NEW_DATA(-(state_offset + count), 0, ncount);
dvander@2762
  1294
        }
dvander@2762
  1295
      break;
dvander@2762
  1296
#endif
dvander@2762
  1297
dvander@2762
  1298
      /*-----------------------------------------------------------------*/
dvander@2762
  1299
      case OP_ANYNL_EXTRA + OP_TYPEQUERY:
dvander@2762
  1300
      case OP_ANYNL_EXTRA + OP_TYPEMINQUERY:
dvander@2762
  1301
      case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY:
dvander@2762
  1302
      count = 2;
dvander@2762
  1303
      goto QS3;
dvander@2762
  1304
dvander@2762
  1305
      case OP_ANYNL_EXTRA + OP_TYPESTAR:
dvander@2762
  1306
      case OP_ANYNL_EXTRA + OP_TYPEMINSTAR:
dvander@2762
  1307
      case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR:
dvander@2762
  1308
      count = 0;
dvander@2762
  1309
dvander@2762
  1310
      QS3:
dvander@2762
  1311
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
  1312
      if (clen > 0)
dvander@2762
  1313
        {
dvander@2762
  1314
        int ncount = 0;
dvander@2762
  1315
        switch (c)
dvander@2762
  1316
          {
dvander@2762
  1317
          case 0x000b:
dvander@2762
  1318
          case 0x000c:
dvander@2762
  1319
          case 0x0085:
dvander@2762
  1320
          case 0x2028:
dvander@2762
  1321
          case 0x2029:
dvander@2762
  1322
          if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
dvander@2762
  1323
          goto ANYNL02;
dvander@2762
  1324
dvander@2762
  1325
          case 0x000d:
dvander@2762
  1326
          if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1;
dvander@2762
  1327
          /* Fall through */
dvander@2762
  1328
dvander@2762
  1329
          ANYNL02:
dvander@2762
  1330
          case 0x000a:
dvander@2762
  1331
          if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR ||
dvander@2762
  1332
              codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY)
dvander@2762
  1333
            {
dvander@2762
  1334
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1335
            next_active_state--;
dvander@2762
  1336
            }
dvander@2762
  1337
          ADD_NEW_DATA(-(state_offset + count), 0, ncount);
dvander@2762
  1338
          break;
dvander@2762
  1339
dvander@2762
  1340
          default:
dvander@2762
  1341
          break;
dvander@2762
  1342
          }
dvander@2762
  1343
        }
dvander@2762
  1344
      break;
dvander@2762
  1345
dvander@2762
  1346
      /*-----------------------------------------------------------------*/
dvander@2762
  1347
      case OP_VSPACE_EXTRA + OP_TYPEQUERY:
dvander@2762
  1348
      case OP_VSPACE_EXTRA + OP_TYPEMINQUERY:
dvander@2762
  1349
      case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY:
dvander@2762
  1350
      count = 2;
dvander@2762
  1351
      goto QS4;
dvander@2762
  1352
dvander@2762
  1353
      case OP_VSPACE_EXTRA + OP_TYPESTAR:
dvander@2762
  1354
      case OP_VSPACE_EXTRA + OP_TYPEMINSTAR:
dvander@2762
  1355
      case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR:
dvander@2762
  1356
      count = 0;
dvander@2762
  1357
dvander@2762
  1358
      QS4:
dvander@2762
  1359
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
  1360
      if (clen > 0)
dvander@2762
  1361
        {
dvander@2762
  1362
        BOOL OK;
dvander@2762
  1363
        switch (c)
dvander@2762
  1364
          {
dvander@2762
  1365
          case 0x000a:
dvander@2762
  1366
          case 0x000b:
dvander@2762
  1367
          case 0x000c:
dvander@2762
  1368
          case 0x000d:
dvander@2762
  1369
          case 0x0085:
dvander@2762
  1370
          case 0x2028:
dvander@2762
  1371
          case 0x2029:
dvander@2762
  1372
          OK = TRUE;
dvander@2762
  1373
          break;
dvander@2762
  1374
dvander@2762
  1375
          default:
dvander@2762
  1376
          OK = FALSE;
dvander@2762
  1377
          break;
dvander@2762
  1378
          }
dvander@2762
  1379
        if (OK == (d == OP_VSPACE))
dvander@2762
  1380
          {
dvander@2762
  1381
          if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR ||
dvander@2762
  1382
              codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY)
dvander@2762
  1383
            {
dvander@2762
  1384
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1385
            next_active_state--;
dvander@2762
  1386
            }
dvander@2762
  1387
          ADD_NEW_DATA(-(state_offset + count), 0, 0);
dvander@2762
  1388
          }
dvander@2762
  1389
        }
dvander@2762
  1390
      break;
dvander@2762
  1391
dvander@2762
  1392
      /*-----------------------------------------------------------------*/
dvander@2762
  1393
      case OP_HSPACE_EXTRA + OP_TYPEQUERY:
dvander@2762
  1394
      case OP_HSPACE_EXTRA + OP_TYPEMINQUERY:
dvander@2762
  1395
      case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY:
dvander@2762
  1396
      count = 2;
dvander@2762
  1397
      goto QS5;
dvander@2762
  1398
dvander@2762
  1399
      case OP_HSPACE_EXTRA + OP_TYPESTAR:
dvander@2762
  1400
      case OP_HSPACE_EXTRA + OP_TYPEMINSTAR:
dvander@2762
  1401
      case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR:
dvander@2762
  1402
      count = 0;
dvander@2762
  1403
dvander@2762
  1404
      QS5:
dvander@2762
  1405
      ADD_ACTIVE(state_offset + 2, 0);
dvander@2762
  1406
      if (clen > 0)
dvander@2762
  1407
        {
dvander@2762
  1408
        BOOL OK;
dvander@2762
  1409
        switch (c)
dvander@2762
  1410
          {
dvander@2762
  1411
          case 0x09:      /* HT */
dvander@2762
  1412
          case 0x20:      /* SPACE */
dvander@2762
  1413
          case 0xa0:      /* NBSP */
dvander@2762
  1414
          case 0x1680:    /* OGHAM SPACE MARK */
dvander@2762
  1415
          case 0x180e:    /* MONGOLIAN VOWEL SEPARATOR */
dvander@2762
  1416
          case 0x2000:    /* EN QUAD */
dvander@2762
  1417
          case 0x2001:    /* EM QUAD */
dvander@2762
  1418
          case 0x2002:    /* EN SPACE */
dvander@2762
  1419
          case 0x2003:    /* EM SPACE */
dvander@2762
  1420
          case 0x2004:    /* THREE-PER-EM SPACE */
dvander@2762
  1421
          case 0x2005:    /* FOUR-PER-EM SPACE */
dvander@2762
  1422
          case 0x2006:    /* SIX-PER-EM SPACE */
dvander@2762
  1423
          case 0x2007:    /* FIGURE SPACE */
dvander@2762
  1424
          case 0x2008:    /* PUNCTUATION SPACE */
dvander@2762
  1425
          case 0x2009:    /* THIN SPACE */
dvander@2762
  1426
          case 0x200A:    /* HAIR SPACE */
dvander@2762
  1427
          case 0x202f:    /* NARROW NO-BREAK SPACE */
dvander@2762
  1428
          case 0x205f:    /* MEDIUM MATHEMATICAL SPACE */
dvander@2762
  1429
          case 0x3000:    /* IDEOGRAPHIC SPACE */
dvander@2762
  1430
          OK = TRUE;
dvander@2762
  1431
          break;
dvander@2762
  1432
dvander@2762
  1433
          default:
dvander@2762
  1434
          OK = FALSE;
dvander@2762
  1435
          break;
dvander@2762
  1436
          }
dvander@2762
  1437
dvander@2762
  1438
        if (OK == (d == OP_HSPACE))
dvander@2762
  1439
          {
dvander@2762
  1440
          if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR ||
dvander@2762
  1441
              codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY)
dvander@2762
  1442
            {
dvander@2762
  1443
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1444
            next_active_state--;
dvander@2762
  1445
            }
dvander@2762
  1446
          ADD_NEW_DATA(-(state_offset + count), 0, 0);
dvander@2762
  1447
          }
dvander@2762
  1448
        }
dvander@2762
  1449
      break;
dvander@2762
  1450
dvander@2762
  1451
      /*-----------------------------------------------------------------*/
dvander@2762
  1452
#ifdef SUPPORT_UCP
dvander@2762
  1453
      case OP_PROP_EXTRA + OP_TYPEEXACT:
dvander@2762
  1454
      case OP_PROP_EXTRA + OP_TYPEUPTO:
dvander@2762
  1455
      case OP_PROP_EXTRA + OP_TYPEMINUPTO:
dvander@2762
  1456
      case OP_PROP_EXTRA + OP_TYPEPOSUPTO:
dvander@2762
  1457
      if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT)
dvander@2762
  1458
        { ADD_ACTIVE(state_offset + 6, 0); }
dvander@2762
  1459
      count = current_state->count;  /* Number already matched */
dvander@2762
  1460
      if (clen > 0)
dvander@2762
  1461
        {
dvander@2762
  1462
        BOOL OK;
dvander@2762
  1463
        const ucd_record * prop = GET_UCD(c);
dvander@2762
  1464
        switch(code[4])
dvander@2762
  1465
          {
dvander@2762
  1466
          case PT_ANY:
dvander@2762
  1467
          OK = TRUE;
dvander@2762
  1468
          break;
dvander@2762
  1469
dvander@2762
  1470
          case PT_LAMP:
dvander@2762
  1471
          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt;
dvander@2762
  1472
          break;
dvander@2762
  1473
dvander@2762
  1474
          case PT_GC:
dvander@2762
  1475
          OK = _pcre_ucp_gentype[prop->chartype] == code[5];
dvander@2762
  1476
          break;
dvander@2762
  1477
dvander@2762
  1478
          case PT_PC:
dvander@2762
  1479
          OK = prop->chartype == code[5];
dvander@2762
  1480
          break;
dvander@2762
  1481
dvander@2762
  1482
          case PT_SC:
dvander@2762
  1483
          OK = prop->script == code[5];
dvander@2762
  1484
          break;
dvander@2762
  1485
dvander@2762
  1486
          /* Should never occur, but keep compilers from grumbling. */
dvander@2762
  1487
dvander@2762
  1488
          default:
dvander@2762
  1489
          OK = codevalue != OP_PROP;
dvander@2762
  1490
          break;
dvander@2762
  1491
          }
dvander@2762
  1492
dvander@2762
  1493
        if (OK == (d == OP_PROP))
dvander@2762
  1494
          {
dvander@2762
  1495
          if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO)
dvander@2762
  1496
            {
dvander@2762
  1497
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1498
            next_active_state--;
dvander@2762
  1499
            }
dvander@2762
  1500
          if (++count >= GET2(code, 1))
dvander@2762
  1501
            { ADD_NEW(state_offset + 6, 0); }
dvander@2762
  1502
          else
dvander@2762
  1503
            { ADD_NEW(state_offset, count); }
dvander@2762
  1504
          }
dvander@2762
  1505
        }
dvander@2762
  1506
      break;
dvander@2762
  1507
dvander@2762
  1508
      /*-----------------------------------------------------------------*/
dvander@2762
  1509
      case OP_EXTUNI_EXTRA + OP_TYPEEXACT:
dvander@2762
  1510
      case OP_EXTUNI_EXTRA + OP_TYPEUPTO:
dvander@2762
  1511
      case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO:
dvander@2762
  1512
      case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO:
dvander@2762
  1513
      if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT)
dvander@2762
  1514
        { ADD_ACTIVE(state_offset + 4, 0); }
dvander@2762
  1515
      count = current_state->count;  /* Number already matched */
dvander@2762
  1516
      if (clen > 0 && UCD_CATEGORY(c) != ucp_M)
dvander@2762
  1517
        {
dvander@2762
  1518
        const uschar *nptr = ptr + clen;
dvander@2762
  1519
        int ncount = 0;
dvander@2762
  1520
        if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO)
dvander@2762
  1521
          {
dvander@2762
  1522
          active_count--;           /* Remove non-match possibility */
dvander@2762
  1523
          next_active_state--;
dvander@2762
  1524
          }
dvander@2762
  1525
        while (nptr < end_subject)
dvander@2762
  1526
          {
dvander@2762
  1527
          int nd;
dvander@2762
  1528
          int ndlen = 1;
dvander@2762
  1529
          GETCHARLEN(nd, nptr, ndlen);
dvander@2762
  1530
          if (UCD_CATEGORY(nd) != ucp_M) break;
dvander@2762
  1531
          ncount++;
dvander@2762
  1532
          nptr += ndlen;
dvander@2762
  1533
          }
dvander@2762
  1534
        if (++count >= GET2(code, 1))
dvander@2762
  1535
          { ADD_NEW_DATA(-(state_offset + 4), 0, ncount); }
dvander@2762
  1536
        else
dvander@2762
  1537
          { ADD_NEW_DATA(-state_offset, count, ncount); }
dvander@2762
  1538
        }
dvander@2762
  1539
      break;
dvander@2762
  1540
#endif
dvander@2762
  1541
dvander@2762
  1542
      /*-----------------------------------------------------------------*/
dvander@2762
  1543
      case OP_ANYNL_EXTRA + OP_TYPEEXACT:
dvander@2762
  1544
      case OP_ANYNL_EXTRA + OP_TYPEUPTO:
dvander@2762
  1545
      case OP_ANYNL_EXTRA + OP_TYPEMINUPTO:
dvander@2762
  1546
      case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO:
dvander@2762
  1547
      if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT)
dvander@2762
  1548
        { ADD_ACTIVE(state_offset + 4, 0); }
dvander@2762
  1549
      count = current_state->count;  /* Number already matched */
dvander@2762
  1550
      if (clen > 0)
dvander@2762
  1551
        {
dvander@2762
  1552
        int ncount = 0;
dvander@2762
  1553
        switch (c)
dvander@2762
  1554
          {
dvander@2762
  1555
          case 0x000b:
dvander@2762
  1556
          case 0x000c:
dvander@2762
  1557
          case 0x0085:
dvander@2762
  1558
          case 0x2028:
dvander@2762
  1559
          case 0x2029:
dvander@2762
  1560
          if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
dvander@2762
  1561
          goto ANYNL03;
dvander@2762
  1562
dvander@2762
  1563
          case 0x000d:
dvander@2762
  1564
          if (ptr + 1 < end_subject && ptr[1] == 0x0a) ncount = 1;
dvander@2762
  1565
          /* Fall through */
dvander@2762
  1566
dvander@2762
  1567
          ANYNL03:
dvander@2762
  1568
          case 0x000a:
dvander@2762
  1569
          if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO)
dvander@2762
  1570
            {
dvander@2762
  1571
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1572
            next_active_state--;
dvander@2762
  1573
            }
dvander@2762
  1574
          if (++count >= GET2(code, 1))
dvander@2762
  1575
            { ADD_NEW_DATA(-(state_offset + 4), 0, ncount); }
dvander@2762
  1576
          else
dvander@2762
  1577
            { ADD_NEW_DATA(-state_offset, count, ncount); }
dvander@2762
  1578
          break;
dvander@2762
  1579
dvander@2762
  1580
          default:
dvander@2762
  1581
          break;
dvander@2762
  1582
          }
dvander@2762
  1583
        }
dvander@2762
  1584
      break;
dvander@2762
  1585
dvander@2762
  1586
      /*-----------------------------------------------------------------*/
dvander@2762
  1587
      case OP_VSPACE_EXTRA + OP_TYPEEXACT:
dvander@2762
  1588
      case OP_VSPACE_EXTRA + OP_TYPEUPTO:
dvander@2762
  1589
      case OP_VSPACE_EXTRA + OP_TYPEMINUPTO:
dvander@2762
  1590
      case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO:
dvander@2762
  1591
      if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT)
dvander@2762
  1592
        { ADD_ACTIVE(state_offset + 4, 0); }
dvander@2762
  1593
      count = current_state->count;  /* Number already matched */
dvander@2762
  1594
      if (clen > 0)
dvander@2762
  1595
        {
dvander@2762
  1596
        BOOL OK;
dvander@2762
  1597
        switch (c)
dvander@2762
  1598
          {
dvander@2762
  1599
          case 0x000a:
dvander@2762
  1600
          case 0x000b:
dvander@2762
  1601
          case 0x000c:
dvander@2762
  1602
          case 0x000d:
dvander@2762
  1603
          case 0x0085:
dvander@2762
  1604
          case 0x2028:
dvander@2762
  1605
          case 0x2029:
dvander@2762
  1606
          OK = TRUE;
dvander@2762
  1607
          break;
dvander@2762
  1608
dvander@2762
  1609
          default:
dvander@2762
  1610
          OK = FALSE;
dvander@2762
  1611
          }
dvander@2762
  1612
dvander@2762
  1613
        if (OK == (d == OP_VSPACE))
dvander@2762
  1614
          {
dvander@2762
  1615
          if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO)
dvander@2762
  1616
            {
dvander@2762
  1617
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1618
            next_active_state--;
dvander@2762
  1619
            }
dvander@2762
  1620
          if (++count >= GET2(code, 1))
dvander@2762
  1621
            { ADD_NEW_DATA(-(state_offset + 4), 0, 0); }
dvander@2762
  1622
          else
dvander@2762
  1623
            { ADD_NEW_DATA(-state_offset, count, 0); }
dvander@2762
  1624
          }
dvander@2762
  1625
        }
dvander@2762
  1626
      break;
dvander@2762
  1627
dvander@2762
  1628
      /*-----------------------------------------------------------------*/
dvander@2762
  1629
      case OP_HSPACE_EXTRA + OP_TYPEEXACT:
dvander@2762
  1630
      case OP_HSPACE_EXTRA + OP_TYPEUPTO:
dvander@2762
  1631
      case OP_HSPACE_EXTRA + OP_TYPEMINUPTO:
dvander@2762
  1632
      case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO:
dvander@2762
  1633
      if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT)
dvander@2762
  1634
        { ADD_ACTIVE(state_offset + 4, 0); }
dvander@2762
  1635
      count = current_state->count;  /* Number already matched */
dvander@2762
  1636
      if (clen > 0)
dvander@2762
  1637
        {
dvander@2762
  1638
        BOOL OK;
dvander@2762
  1639
        switch (c)
dvander@2762
  1640
          {
dvander@2762
  1641
          case 0x09:      /* HT */
dvander@2762
  1642
          case 0x20:      /* SPACE */
dvander@2762
  1643
          case 0xa0:      /* NBSP */
dvander@2762
  1644
          case 0x1680:    /* OGHAM SPACE MARK */
dvander@2762
  1645
          case 0x180e:    /* MONGOLIAN VOWEL SEPARATOR */
dvander@2762
  1646
          case 0x2000:    /* EN QUAD */
dvander@2762
  1647
          case 0x2001:    /* EM QUAD */
dvander@2762
  1648
          case 0x2002:    /* EN SPACE */
dvander@2762
  1649
          case 0x2003:    /* EM SPACE */
dvander@2762
  1650
          case 0x2004:    /* THREE-PER-EM SPACE */
dvander@2762
  1651
          case 0x2005:    /* FOUR-PER-EM SPACE */
dvander@2762
  1652
          case 0x2006:    /* SIX-PER-EM SPACE */
dvander@2762
  1653
          case 0x2007:    /* FIGURE SPACE */
dvander@2762
  1654
          case 0x2008:    /* PUNCTUATION SPACE */
dvander@2762
  1655
          case 0x2009:    /* THIN SPACE */
dvander@2762
  1656
          case 0x200A:    /* HAIR SPACE */
dvander@2762
  1657
          case 0x202f:    /* NARROW NO-BREAK SPACE */
dvander@2762
  1658
          case 0x205f:    /* MEDIUM MATHEMATICAL SPACE */
dvander@2762
  1659
          case 0x3000:    /* IDEOGRAPHIC SPACE */
dvander@2762
  1660
          OK = TRUE;
dvander@2762
  1661
          break;
dvander@2762
  1662
dvander@2762
  1663
          default:
dvander@2762
  1664
          OK = FALSE;
dvander@2762
  1665
          break;
dvander@2762
  1666
          }
dvander@2762
  1667
dvander@2762
  1668
        if (OK == (d == OP_HSPACE))
dvander@2762
  1669
          {
dvander@2762
  1670
          if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO)
dvander@2762
  1671
            {
dvander@2762
  1672
            active_count--;           /* Remove non-match possibility */
dvander@2762
  1673
            next_active_state--;
dvander@2762
  1674
            }
dvander@2762
  1675
          if (++count >= GET2(code, 1))
dvander@2762
  1676
            { ADD_NEW_DATA(-(state_offset + 4), 0, 0); }
dvander@2762
  1677
          else
dvander@2762
  1678
            { ADD_NEW_DATA(-state_offset, count, 0); }
dvander@2762
  1679
          }
dvander@2762
  1680
        }
dvander@2762
  1681
      break;
dvander@2762
  1682
dvander@2762
  1683
/* ========================================================================== */
dvander@2762
  1684
      /* These opcodes are followed by a character that is usually compared
dvander@2762
  1685
      to the current subject character; it is loaded into d. We still get
dvander@2762
  1686
      here even if there is no subject character, because in some cases zero
dvander@2762
  1687
      repetitions are permitted. */
dvander@2762
  1688
dvander@2762
  1689
      /*-----------------------------------------------------------------*/
dvander@2762
  1690
      case OP_CHAR:
dvander@2762
  1691
      if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); }
dvander@2762
  1692
      break;
dvander@2762
  1693
dvander@2762
  1694
      /*-----------------------------------------------------------------*/
dvander@2762
  1695
      case OP_CHARNC:
dvander@2762
  1696
      if (clen == 0) break;
dvander@2762
  1697
dvander@2762
  1698
#ifdef SUPPORT_UTF8
dvander@2762
  1699
      if (utf8)
dvander@2762
  1700
        {
dvander@2762
  1701
        if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else
dvander@2762
  1702
          {
dvander@2762
  1703
          unsigned int othercase;
dvander@2762
  1704
          if (c < 128) othercase = fcc[c]; else
dvander@2762
  1705
dvander@2762
  1706
          /* If we have Unicode property support, we can use it to test the
dvander@2762
  1707
          other case of the character. */
dvander@2762
  1708
dvander@2762
  1709
#ifdef SUPPORT_UCP
dvander@2762
  1710
          othercase = UCD_OTHERCASE(c);
dvander@2762
  1711
#else
dvander@2762
  1712
          othercase = NOTACHAR;
dvander@2762
  1713
#endif
dvander@2762
  1714
dvander@2762
  1715
          if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); }
dvander@2762
  1716
          }
dvander@2762
  1717
        }
dvander@2762
  1718
      else
dvander@2762
  1719
#endif  /* SUPPORT_UTF8 */
dvander@2762
  1720
dvander@2762
  1721
      /* Non-UTF-8 mode */
dvander@2762
  1722
        {
dvander@2762
  1723
        if (lcc[c] == lcc[d]) { ADD_NEW(state_offset + 2, 0); }
dvander@2762
  1724
        }
dvander@2762
  1725
      break;
dvander@2762
  1726
dvander@2762
  1727
dvander@2762
  1728
#ifdef SUPPORT_UCP
dvander@2762
  1729
      /*-----------------------------------------------------------------*/
dvander@2762
  1730
      /* This is a tricky one because it can match more than one character.
dvander@2762
  1731
      Find out how many characters to skip, and then set up a negative state
dvander@2762
  1732
      to wait for them to pass before continuing. */
dvander@2762
  1733
dvander@2762
  1734
      case OP_EXTUNI:
dvander@2762
  1735
      if (clen > 0 && UCD_CATEGORY(c) != ucp_M)
dvander@2762
  1736
        {
dvander@2762
  1737
        const uschar *nptr = ptr + clen;
dvander@2762
  1738
        int ncount = 0;
dvander@2762
  1739
        while (nptr < end_subject)
dvander@2762
  1740
          {
dvander@2762
  1741
          int nclen = 1;
dvander@2762
  1742
          GETCHARLEN(c, nptr, nclen);
dvander@2762
  1743
          if (UCD_CATEGORY(c) != ucp_M) break;
dvander@2762
  1744
          ncount++;
dvander@2762
  1745
          nptr += nclen;
dvander@2762
  1746
          }
dvander@2762
  1747
        ADD_NEW_DATA(-(state_offset + 1), 0, ncount);
dvander@2762
  1748
        }
dvander@2762
  1749
      break;
dvander@2762
  1750
#endif
dvander@2762
  1751
dvander@2762
  1752
      /*-----------------------------------------------------------------*/
dvander@2762
  1753
      /* This is a tricky like EXTUNI because it too can match more than one
dvander@2762
  1754
      character (when CR is followed by LF). In this case, set up a negative
dvander@2762
  1755
      state to wait for one character to pass before continuing. */
dvander@2762
  1756
dvander@2762
  1757
      case OP_ANYNL:
dvander@2762
  1758
      if (clen > 0) switch(c)
dvander@2762
  1759
        {
dvander@2762
  1760
        case 0x000b:
dvander@2762
  1761
        case 0x000c:
dvander@2762
  1762
        case 0x0085:
dvander@2762
  1763
        case 0x2028:
dvander@2762
  1764
        case 0x2029:
dvander@2762
  1765
        if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
dvander@2762
  1766
dvander@2762
  1767
        case 0x000a:
dvander@2762
  1768
        ADD_NEW(state_offset + 1, 0);
dvander@2762
  1769
        break;
dvander@2762
  1770
dvander@2762
  1771
        case 0x000d:
dvander@2762
  1772
        if (ptr + 1 < end_subject && ptr[1] == 0x0a)
dvander@2762
  1773
          {
dvander@2762
  1774
          ADD_NEW_DATA(-(state_offset + 1), 0, 1);
dvander@2762
  1775
          }
dvander@2762
  1776
        else
dvander@2762
  1777
          {
dvander@2762
  1778
          ADD_NEW(state_offset + 1, 0);
dvander@2762
  1779
          }
dvander@2762
  1780
        break;
dvander@2762
  1781
        }
dvander@2762
  1782
      break;
dvander@2762
  1783
dvander@2762
  1784
      /*-----------------------------------------------------------------*/
dvander@2762
  1785
      case OP_NOT_VSPACE:
dvander@2762
  1786
      if (clen > 0) switch(c)
dvander@2762
  1787
        {
dvander@2762
  1788
        case 0x000a:
dvander@2762
  1789
        case 0x000b:
dvander@2762
  1790
        case 0x000c:
dvander@2762
  1791
        case 0x000d:
dvander@2762
  1792
        case 0x0085:
dvander@2762
  1793
        case 0x2028:
dvander@2762
  1794
        case 0x2029:
dvander@2762
  1795
        break;
dvander@2762
  1796
dvander@2762
  1797
        default:
dvander@2762
  1798
        ADD_NEW(state_offset + 1, 0);
dvander@2762
  1799
        break;
dvander@2762
  1800
        }
dvander@2762
  1801
      break;
dvander@2762
  1802
dvander@2762
  1803
      /*-----------------------------------------------------------------*/
dvander@2762
  1804
      case OP_VSPACE:
dvander@2762
  1805
      if (clen > 0) switch(c)
dvander@2762
  1806
        {
dvander@2762
  1807
        case 0x000a:
dvander@2762
  1808
        case 0x000b:
dvander@2762
  1809
        case 0x000c:
dvander@2762
  1810
        case 0x000d:
dvander@2762
  1811
        case 0x0085:
dvander@2762
  1812
        case 0x2028:
dvander@2762
  1813
        case 0x2029:
dvander@2762
  1814
        ADD_NEW(state_offset + 1, 0);
dvander@2762
  1815
        break;
dvander@2762
  1816
dvander@2762
  1817
        default: break;
dvander@2762
  1818
        }
dvander@2762
  1819
      break;
dvander@2762
  1820
dvander@2762
  1821
      /*-----------------------------------------------------------------*/
dvander@2762
  1822
      case OP_NOT_HSPACE:
dvander@2762
  1823
      if (clen > 0) switch(c)
dvander@2762
  1824
        {
dvander@2762
  1825
        case 0x09:      /* HT */
dvander@2762
  1826
        case 0x20:      /* SPACE */
dvander@2762
  1827
        case 0xa0:      /* NBSP */
dvander@2762
  1828
        case 0x1680:    /* OGHAM SPACE MARK */
dvander@2762
  1829
        case 0x180e:    /* MONGOLIAN VOWEL SEPARATOR */
dvander@2762
  1830
        case 0x2000:    /* EN QUAD */
dvander@2762
  1831
        case 0x2001:    /* EM QUAD */
dvander@2762
  1832
        case 0x2002:    /* EN SPACE */
dvander@2762
  1833
        case 0x2003:    /* EM SPACE */
dvander@2762
  1834
        case 0x2004:    /* THREE-PER-EM SPACE */
dvander@2762
  1835
        case 0x2005:    /* FOUR-PER-EM SPACE */
dvander@2762
  1836
        case 0x2006:    /* SIX-PER-EM SPACE */
dvander@2762
  1837
        case 0x2007:    /* FIGURE SPACE */
dvander@2762
  1838
        case 0x2008:    /* PUNCTUATION SPACE */
dvander@2762
  1839
        case 0x2009:    /* THIN SPACE */
dvander@2762
  1840
        case 0x200A:    /* HAIR SPACE */
dvander@2762
  1841
        case 0x202f:    /* NARROW NO-BREAK SPACE */
dvander@2762
  1842
        case 0x205f:    /* MEDIUM MATHEMATICAL SPACE */
dvander@2762
  1843
        case 0x3000:    /* IDEOGRAPHIC SPACE */
dvander@2762
  1844
        break;
dvander@2762
  1845
dvander@2762
  1846
        default:
dvander@2762
  1847
        ADD_NEW(state_offset + 1, 0);
dvander@2762
  1848
        break;
dvander@2762
  1849
        }
dvander@2762
  1850
      break;
dvander@2762
  1851
dvander@2762
  1852
      /*-----------------------------------------------------------------*/
dvander@2762
  1853
      case OP_HSPACE:
dvander@2762
  1854
      if (clen > 0) switch(c)
dvander@2762
  1855
        {
dvander@2762
  1856
        case 0x09:      /* HT */
dvander@2762
  1857
        case 0x20:      /* SPACE */
dvander@2762
  1858
        case 0xa0:      /* NBSP */
dvander@2762
  1859
        case 0x1680:    /* OGHAM SPACE MARK */
dvander@2762
  1860
        case 0x180e:    /* MONGOLIAN VOWEL SEPARATOR */
dvander@2762
  1861
        case 0x2000:    /* EN QUAD */
dvander@2762
  1862
        case 0x2001:    /* EM QUAD */
dvander@2762
  1863
        case 0x2002:    /* EN SPACE */
dvander@2762
  1864
        case 0x2003:    /* EM SPACE */
dvander@2762
  1865
        case 0x2004:    /* THREE-PER-EM SPACE */
dvander@2762
  1866
        case 0x2005:    /* FOUR-PER-EM SPACE */
dvander@2762
  1867
        case 0x2006:    /* SIX-PER-EM SPACE */
dvander@2762
  1868
        case 0x2007:    /* FIGURE SPACE */
dvander@2762
  1869
        case 0x2008:    /* PUNCTUATION SPACE */
dvander@2762
  1870
        case 0x2009:    /* THIN SPACE */
dvander@2762
  1871
        case 0x200A:    /* HAIR SPACE */
dvander@2762
  1872
        case 0x202f:    /* NARROW NO-BREAK SPACE */
dvander@2762
  1873
        case 0x205f:    /* MEDIUM MATHEMATICAL SPACE */
dvander@2762
  1874
        case 0x3000:    /* IDEOGRAPHIC SPACE */
dvander@2762
  1875
        ADD_NEW(state_offset + 1, 0);
dvander@2762
  1876
        break;
dvander@2762
  1877
        }
dvander@2762
  1878
      break;
dvander@2762
  1879
dvander@2762
  1880
      /*-----------------------------------------------------------------*/
dvander@2762
  1881
      /* Match a negated single character. This is only used for one-byte
dvander@2762
  1882
      characters, that is, we know that d < 256. The character we are
dvander@2762
  1883
      checking (c) can be multibyte. */
dvander@2762
  1884
dvander@2762
  1885
      case OP_NOT:
dvander@2762
  1886
      if (clen > 0)
dvander@2762
  1887
        {
dvander@2762
  1888
        unsigned int otherd = ((ims & PCRE_CASELESS) != 0)? fcc[d] : d;
dvander@2762
  1889
        if (c != d && c != otherd) { ADD_NEW(state_offset + dlen + 1, 0); }
dvander@2762
  1890
        }
dvander@2762
  1891
      break;
dvander@2762
  1892
dvander@2762
  1893
      /*-----------------------------------------------------------------*/
dvander@2762
  1894
      case OP_PLUS:
dvander@2762
  1895
      case OP_MINPLUS:
dvander@2762
  1896
      case OP_POSPLUS:
dvander@2762
  1897
      case OP_NOTPLUS:
dvander@2762
  1898
      case OP_NOTMINPLUS:
dvander@2762
  1899
      case OP_NOTPOSPLUS:
dvander@2762
  1900
      count = current_state->count;  /* Already matched */
dvander@2762
  1901
      if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); }
dvander@2762
  1902
      if (clen > 0)
dvander@2762
  1903
        {
dvander@2762
  1904
        unsigned int otherd = NOTACHAR;
dvander@2762
  1905
        if ((ims & PCRE_CASELESS) != 0)
dvander@2762
  1906
          {
dvander@2762
  1907
#ifdef SUPPORT_UTF8
dvander@2762
  1908
          if (utf8 && d >= 128)
dvander@2762
  1909
            {
dvander@2762
  1910
#ifdef SUPPORT_UCP
dvander@2762
  1911
            otherd = UCD_OTHERCASE(d);
dvander@2762
  1912
#endif  /* SUPPORT_UCP */
dvander@2762
  1913
            }
dvander@2762
  1914
          else
dvander@2762
  1915
#endif  /* SUPPORT_UTF8 */
dvander@2762
  1916
          otherd = fcc[d];
dvander@2762
  1917
          }
dvander@2762
  1918
        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
dvander@2762
  1919
          {
dvander@2762
  1920
          if (count > 0 &&
dvander@2762
  1921
              (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS))
dvander@2762
  1922
            {
dvander@2762
  1923
            active_count--;             /* Remove non-match possibility */
dvander@2762
  1924
            next_active_state--;
dvander@2762
  1925
            }
dvander@2762
  1926
          count++;
dvander@2762
  1927
          ADD_NEW(state_offset, count);
dvander@2762
  1928
          }
dvander@2762
  1929
        }
dvander@2762
  1930
      break;
dvander@2762
  1931
dvander@2762
  1932
      /*-----------------------------------------------------------------*/
dvander@2762
  1933
      case OP_QUERY:
dvander@2762
  1934
      case OP_MINQUERY:
dvander@2762
  1935
      case OP_POSQUERY:
dvander@2762
  1936
      case OP_NOTQUERY:
dvander@2762
  1937
      case OP_NOTMINQUERY:
dvander@2762
  1938
      case OP_NOTPOSQUERY:
dvander@2762
  1939
      ADD_ACTIVE(state_offset + dlen + 1, 0);
dvander@2762
  1940
      if (clen > 0)
dvander@2762
  1941
        {
dvander@2762
  1942
        unsigned int otherd = NOTACHAR;
dvander@2762
  1943
        if ((ims & PCRE_CASELESS) != 0)
dvander@2762
  1944
          {
dvander@2762
  1945
#ifdef SUPPORT_UTF8
dvander@2762
  1946
          if (utf8 && d >= 128)
dvander@2762
  1947
            {
dvander@2762
  1948
#ifdef SUPPORT_UCP
dvander@2762
  1949
            otherd = UCD_OTHERCASE(d);
dvander@2762
  1950
#endif  /* SUPPORT_UCP */
dvander@2762
  1951
            }
dvander@2762
  1952
          else
dvander@2762
  1953
#endif  /* SUPPORT_UTF8 */
dvander@2762
  1954
          otherd = fcc[d];
dvander@2762
  1955
          }
dvander@2762
  1956
        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
dvander@2762
  1957
          {
dvander@2762
  1958
          if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY)
dvander@2762
  1959
            {
dvander@2762
  1960
            active_count--;            /* Remove non-match possibility */
dvander@2762
  1961
            next_active_state--;
dvander@2762
  1962
            }
dvander@2762
  1963
          ADD_NEW(state_offset + dlen + 1, 0);
dvander@2762
  1964
          }
dvander@2762
  1965
        }
dvander@2762
  1966
      break;
dvander@2762
  1967
dvander@2762
  1968
      /*-----------------------------------------------------------------*/
dvander@2762
  1969
      case OP_STAR:
dvander@2762
  1970
      case OP_MINSTAR:
dvander@2762
  1971
      case OP_POSSTAR:
dvander@2762
  1972
      case OP_NOTSTAR:
dvander@2762
  1973
      case OP_NOTMINSTAR:
dvander@2762
  1974
      case OP_NOTPOSSTAR:
dvander@2762
  1975
      ADD_ACTIVE(state_offset + dlen + 1, 0);
dvander@2762
  1976
      if (clen > 0)
dvander@2762
  1977
        {
dvander@2762
  1978
        unsigned int otherd = NOTACHAR;
dvander@2762
  1979
        if ((ims & PCRE_CASELESS) != 0)
dvander@2762
  1980
          {
dvander@2762
  1981
#ifdef SUPPORT_UTF8
dvander@2762
  1982
          if (utf8 && d >= 128)
dvander@2762
  1983
            {
dvander@2762
  1984
#ifdef SUPPORT_UCP
dvander@2762
  1985
            otherd = UCD_OTHERCASE(d);
dvander@2762
  1986
#endif  /* SUPPORT_UCP */
dvander@2762
  1987
            }
dvander@2762
  1988
          else
dvander@2762
  1989
#endif  /* SUPPORT_UTF8 */
dvander@2762
  1990
          otherd = fcc[d];
dvander@2762
  1991
          }
dvander@2762
  1992
        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
dvander@2762
  1993
          {
dvander@2762
  1994
          if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR)
dvander@2762
  1995
            {
dvander@2762
  1996
            active_count--;            /* Remove non-match possibility */
dvander@2762
  1997
            next_active_state--;
dvander@2762
  1998
            }
dvander@2762
  1999
          ADD_NEW(state_offset, 0);
dvander@2762
  2000
          }
dvander@2762
  2001
        }
dvander@2762
  2002
      break;
dvander@2762
  2003
dvander@2762
  2004
      /*-----------------------------------------------------------------*/
dvander@2762
  2005
      case OP_EXACT:
dvander@2762
  2006
      case OP_NOTEXACT:
dvander@2762
  2007
      count = current_state->count;  /* Number already matched */
dvander@2762
  2008
      if (clen > 0)
dvander@2762
  2009
        {
dvander@2762
  2010
        unsigned int otherd = NOTACHAR;
dvander@2762
  2011
        if ((ims & PCRE_CASELESS) != 0)
dvander@2762
  2012
          {
dvander@2762
  2013
#ifdef SUPPORT_UTF8
dvander@2762
  2014
          if (utf8 && d >= 128)
dvander@2762
  2015
            {
dvander@2762
  2016
#ifdef SUPPORT_UCP
dvander@2762
  2017
            otherd = UCD_OTHERCASE(d);
dvander@2762
  2018
#endif  /* SUPPORT_UCP */
dvander@2762
  2019
            }
dvander@2762
  2020
          else
dvander@2762
  2021
#endif  /* SUPPORT_UTF8 */
dvander@2762
  2022
          otherd = fcc[d];
dvander@2762
  2023
          }
dvander@2762
  2024
        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
dvander@2762
  2025
          {
dvander@2762
  2026
          if (++count >= GET2(code, 1))
dvander@2762
  2027
            { ADD_NEW(state_offset + dlen + 3, 0); }
dvander@2762
  2028
          else
dvander@2762
  2029
            { ADD_NEW(state_offset, count); }
dvander@2762
  2030
          }
dvander@2762
  2031
        }
dvander@2762
  2032
      break;
dvander@2762
  2033
dvander@2762
  2034
      /*-----------------------------------------------------------------*/
dvander@2762
  2035
      case OP_UPTO:
dvander@2762
  2036
      case OP_MINUPTO:
dvander@2762
  2037
      case OP_POSUPTO:
dvander@2762
  2038
      case OP_NOTUPTO:
dvander@2762
  2039
      case OP_NOTMINUPTO:
dvander@2762
  2040
      case OP_NOTPOSUPTO:
dvander@2762
  2041
      ADD_ACTIVE(state_offset + dlen + 3, 0);
dvander@2762
  2042
      count = current_state->count;  /* Number already matched */
dvander@2762
  2043
      if (clen > 0)
dvander@2762
  2044
        {
dvander@2762
  2045
        unsigned int otherd = NOTACHAR;
dvander@2762
  2046
        if ((ims & PCRE_CASELESS) != 0)
dvander@2762
  2047
          {
dvander@2762
  2048
#ifdef SUPPORT_UTF8
dvander@2762
  2049
          if (utf8 && d >= 128)
dvander@2762
  2050
            {
dvander@2762
  2051
#ifdef SUPPORT_UCP
dvander@2762
  2052
            otherd = UCD_OTHERCASE(d);
dvander@2762
  2053
#endif  /* SUPPORT_UCP */
dvander@2762
  2054
            }
dvander@2762
  2055
          else
dvander@2762
  2056
#endif  /* SUPPORT_UTF8 */
dvander@2762
  2057
          otherd = fcc[d];
dvander@2762
  2058
          }
dvander@2762
  2059
        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
dvander@2762
  2060
          {
dvander@2762
  2061
          if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO)
dvander@2762
  2062
            {
dvander@2762
  2063
            active_count--;             /* Remove non-match possibility */
dvander@2762
  2064
            next_active_state--;
dvander@2762
  2065
            }
dvander@2762
  2066
          if (++count >= GET2(code, 1))
dvander@2762
  2067
            { ADD_NEW(state_offset + dlen + 3, 0); }
dvander@2762
  2068
          else
dvander@2762
  2069
            { ADD_NEW(state_offset, count); }
dvander@2762
  2070
          }
dvander@2762
  2071
        }
dvander@2762
  2072
      break;
dvander@2762
  2073
dvander@2762
  2074
dvander@2762
  2075
/* ========================================================================== */
dvander@2762
  2076
      /* These are the class-handling opcodes */
dvander@2762
  2077
dvander@2762
  2078
      case OP_CLASS:
dvander@2762
  2079
      case OP_NCLASS:
dvander@2762
  2080
      case OP_XCLASS:
dvander@2762
  2081
        {
dvander@2762
  2082
        BOOL isinclass = FALSE;
dvander@2762
  2083
        int next_state_offset;
dvander@2762
  2084
        const uschar *ecode;
dvander@2762
  2085
dvander@2762
  2086
        /* For a simple class, there is always just a 32-byte table, and we
dvander@2762
  2087
        can set isinclass from it. */
dvander@2762
  2088
dvander@2762
  2089
        if (codevalue != OP_XCLASS)
dvander@2762
  2090
          {
dvander@2762
  2091
          ecode = code + 33;
dvander@2762
  2092
          if (clen > 0)
dvander@2762
  2093
            {
dvander@2762
  2094
            isinclass = (c > 255)? (codevalue == OP_NCLASS) :
dvander@2762
  2095
              ((code[1 + c/8] & (1 << (c&7))) != 0);
dvander@2762
  2096
            }
dvander@2762
  2097
          }
dvander@2762
  2098
dvander@2762
  2099
        /* An extended class may have a table or a list of single characters,
dvander@2762
  2100
        ranges, or both, and it may be positive or negative. There's a
dvander@2762
  2101
        function that sorts all this out. */
dvander@2762
  2102
dvander@2762
  2103
        else
dvander@2762
  2104
         {
dvander@2762
  2105
         ecode = code + GET(code, 1);
dvander@2762
  2106
         if (clen > 0) isinclass = _pcre_xclass(c, code + 1 + LINK_SIZE);
dvander@2762
  2107
         }
dvander@2762
  2108
dvander@2762
  2109
        /* At this point, isinclass is set for all kinds of class, and ecode
dvander@2762
  2110
        points to the byte after the end of the class. If there is a
dvander@2762
  2111
        quantifier, this is where it will be. */
dvander@2762
  2112
dvander@2762
  2113
        next_state_offset = ecode - start_code;
dvander@2762
  2114
dvander@2762
  2115
        switch (*ecode)
dvander@2762
  2116
          {
dvander@2762
  2117
          case OP_CRSTAR:
dvander@2762
  2118
          case OP_CRMINSTAR:
dvander@2762
  2119
          ADD_ACTIVE(next_state_offset + 1, 0);
dvander@2762
  2120
          if (isinclass) { ADD_NEW(state_offset, 0); }
dvander@2762
  2121
          break;
dvander@2762
  2122
dvander@2762
  2123
          case OP_CRPLUS:
dvander@2762
  2124
          case OP_CRMINPLUS:
dvander@2762
  2125
          count = current_state->count;  /* Already matched */
dvander@2762
  2126
          if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); }
dvander@2762
  2127
          if (isinclass) { count++; ADD_NEW(state_offset, count); }
dvander@2762
  2128
          break;
dvander@2762
  2129
dvander@2762
  2130
          case OP_CRQUERY:
dvander@2762
  2131
          case OP_CRMINQUERY:
dvander@2762
  2132
          ADD_ACTIVE(next_state_offset + 1, 0);
dvander@2762
  2133
          if (isinclass) { ADD_NEW(next_state_offset + 1, 0); }
dvander@2762
  2134
          break;
dvander@2762
  2135
dvander@2762
  2136
          case OP_CRRANGE:
dvander@2762
  2137
          case OP_CRMINRANGE:
dvander@2762
  2138
          count = current_state->count;  /* Already matched */
dvander@2762
  2139
          if (count >= GET2(ecode, 1))
dvander@2762
  2140
            { ADD_ACTIVE(next_state_offset + 5, 0); }
dvander@2762
  2141
          if (isinclass)
dvander@2762
  2142
            {
dvander@2762
  2143
            int max = GET2(ecode, 3);
dvander@2762
  2144
            if (++count >= max && max != 0)   /* Max 0 => no limit */
dvander@2762
  2145
              { ADD_NEW(next_state_offset + 5, 0); }
dvander@2762
  2146
            else
dvander@2762
  2147
              { ADD_NEW(state_offset, count); }
dvander@2762
  2148
            }
dvander@2762
  2149
          break;
dvander@2762
  2150
dvander@2762
  2151
          default:
dvander@2762
  2152
          if (isinclass) { ADD_NEW(next_state_offset, 0); }
dvander@2762
  2153
          break;
dvander@2762
  2154
          }
dvander@2762
  2155
        }
dvander@2762
  2156
      break;
dvander@2762
  2157
dvander@2762
  2158
/* ========================================================================== */
dvander@2762
  2159
      /* These are the opcodes for fancy brackets of various kinds. We have
dvander@2762
  2160
      to use recursion in order to handle them. The "always failing" assersion
dvander@2762
  2161
      (?!) is optimised when compiling to OP_FAIL, so we have to support that,
dvander@2762
  2162
      though the other "backtracking verbs" are not supported. */
dvander@2762
  2163
dvander@2762
  2164
      case OP_FAIL:
dvander@2762
  2165
      break;
dvander@2762
  2166
dvander@2762
  2167
      case OP_ASSERT:
dvander@2762
  2168
      case OP_ASSERT_NOT:
dvander@2762
  2169
      case OP_ASSERTBACK:
dvander@2762
  2170
      case OP_ASSERTBACK_NOT:
dvander@2762
  2171
        {
dvander@2762
  2172
        int rc;
dvander@2762
  2173
        int local_offsets[2];
dvander@2762
  2174
        int local_workspace[1000];
dvander@2762
  2175
        const uschar *endasscode = code + GET(code, 1);
dvander@2762
  2176
dvander@2762
  2177
        while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
dvander@2762
  2178
dvander@2762
  2179
        rc = internal_dfa_exec(
dvander@2762
  2180
          md,                                   /* static match data */
dvander@2762
  2181
          code,                                 /* this subexpression's code */
dvander@2762
  2182
          ptr,                                  /* where we currently are */
dvander@2762
  2183
          ptr - start_subject,                  /* start offset */
dvander@2762
  2184
          local_offsets,                        /* offset vector */
dvander@2762
  2185
          sizeof(local_offsets)/sizeof(int),    /* size of same */
dvander@2762
  2186
          local_workspace,                      /* workspace vector */
dvander@2762
  2187
          sizeof(local_workspace)/sizeof(int),  /* size of same */
dvander@2762
  2188
          ims,                                  /* the current ims flags */
dvander@2762
  2189
          rlevel,                               /* function recursion level */
dvander@2762
  2190
          recursing);                           /* pass on regex recursion */
dvander@2762
  2191
dvander@2762
  2192
        if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK))
dvander@2762
  2193
            { ADD_ACTIVE(endasscode + LINK_SIZE + 1 - start_code, 0); }
dvander@2762
  2194
        }
dvander@2762
  2195
      break;
dvander@2762
  2196
dvander@2762
  2197
      /*-----------------------------------------------------------------*/
dvander@2762
  2198
      case OP_COND:
dvander@2762
  2199
      case OP_SCOND:
dvander@2762
  2200
        {
dvander@2762
  2201
        int local_offsets[1000];
dvander@2762
  2202
        int local_workspace[1000];
dvander@2762
  2203
        int codelink = GET(code, 1);
dvander@2762
  2204
        int condcode;
dvander@2762
  2205
dvander@2762
  2206
        /* Because of the way auto-callout works during compile, a callout item
dvander@2762
  2207
        is inserted between OP_COND and an assertion condition. This does not
dvander@2762
  2208
        happen for the other conditions. */
dvander@2762
  2209
dvander@2762
  2210
        if (code[LINK_SIZE+1] == OP_CALLOUT)
dvander@2762
  2211
          {
dvander@2762
  2212
          rrc = 0;
dvander@2762
  2213
          if (pcre_callout != NULL)
dvander@2762
  2214
            {
dvander@2762
  2215
            pcre_callout_block cb;
dvander@2762
  2216
            cb.version          = 1;   /* Version 1 of the callout block */
dvander@2762
  2217
            cb.callout_number   = code[LINK_SIZE+2];
dvander@2762
  2218
            cb.offset_vector    = offsets;
dvander@2762
  2219
            cb.subject          = (PCRE_SPTR)start_subject;
dvander@2762
  2220
            cb.subject_length   = end_subject - start_subject;
dvander@2762
  2221
            cb.start_match      = current_subject - start_subject;
dvander@2762
  2222
            cb.current_position = ptr - start_subject;
dvander@2762
  2223
            cb.pattern_position = GET(code, LINK_SIZE + 3);
dvander@2762
  2224
            cb.next_item_length = GET(code, 3 + 2*LINK_SIZE);
dvander@2762
  2225
            cb.capture_top      = 1;
dvander@2762
  2226
            cb.capture_last     = -1;
dvander@2762
  2227
            cb.callout_data     = md->callout_data;
dvander@2762
  2228
            if ((rrc = (*pcre_callout)(&cb)) < 0) return rrc;   /* Abandon */
dvander@2762
  2229
            }
dvander@2762
  2230
          if (rrc > 0) break;                      /* Fail this thread */
dvander@2762
  2231
          code += _pcre_OP_lengths[OP_CALLOUT];    /* Skip callout data */
dvander@2762
  2232
          }
dvander@2762
  2233
dvander@2762
  2234
        condcode = code[LINK_SIZE+1];
dvander@2762
  2235
dvander@2762
  2236
        /* Back reference conditions are not supported */
dvander@2762
  2237
dvander@2762
  2238
        if (condcode == OP_CREF) return PCRE_ERROR_DFA_UCOND;
dvander@2762
  2239
dvander@2762
  2240
        /* The DEFINE condition is always false */
dvander@2762
  2241
dvander@2762
  2242
        if (condcode == OP_DEF)
dvander@2762
  2243
          { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
dvander@2762
  2244
dvander@2762
  2245
        /* The only supported version of OP_RREF is for the value RREF_ANY,
dvander@2762
  2246
        which means "test if in any recursion". We can't test for specifically
dvander@2762
  2247
        recursed groups. */
dvander@2762
  2248
dvander@2762
  2249
        else if (condcode == OP_RREF)
dvander@2762
  2250
          {
dvander@2762
  2251
          int value = GET2(code, LINK_SIZE+2);
dvander@2762
  2252
          if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND;
dvander@2762
  2253
          if (recursing > 0)
dvander@2762
  2254
            { ADD_ACTIVE(state_offset + LINK_SIZE + 4, 0); }
dvander@2762
  2255
          else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
dvander@2762
  2256
          }
dvander@2762
  2257
dvander@2762
  2258
        /* Otherwise, the condition is an assertion */
dvander@2762
  2259
dvander@2762
  2260
        else
dvander@2762
  2261
          {
dvander@2762
  2262
          int rc;
dvander@2762
  2263
          const uschar *asscode = code + LINK_SIZE + 1;
dvander@2762
  2264
          const uschar *endasscode = asscode + GET(asscode, 1);
dvander@2762
  2265
dvander@2762
  2266
          while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
dvander@2762
  2267
dvander@2762
  2268
          rc = internal_dfa_exec(
dvander@2762
  2269
            md,                                   /* fixed match data */
dvander@2762
  2270
            asscode,                              /* this subexpression's code */
dvander@2762
  2271
            ptr,                                  /* where we currently are */
dvander@2762
  2272
            ptr - start_subject,                  /* start offset */
dvander@2762
  2273
            local_offsets,                        /* offset vector */
dvander@2762
  2274
            sizeof(local_offsets)/sizeof(int),    /* size of same */
dvander@2762
  2275
            local_workspace,                      /* workspace vector */
dvander@2762
  2276
            sizeof(local_workspace)/sizeof(int),  /* size of same */
dvander@2762
  2277
            ims,                                  /* the current ims flags */
dvander@2762
  2278
            rlevel,                               /* function recursion level */
dvander@2762
  2279
            recursing);                           /* pass on regex recursion */
dvander@2762
  2280
dvander@2762
  2281
          if ((rc >= 0) ==
dvander@2762
  2282
                (condcode == OP_ASSERT || condcode == OP_ASSERTBACK))
dvander@2762
  2283
            { ADD_ACTIVE(endasscode + LINK_SIZE + 1 - start_code, 0); }
dvander@2762
  2284
          else
dvander@2762
  2285
            { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
dvander@2762
  2286
          }
dvander@2762
  2287
        }
dvander@2762
  2288
      break;
dvander@2762
  2289
dvander@2762
  2290
      /*-----------------------------------------------------------------*/
dvander@2762
  2291
      case OP_RECURSE:
dvander@2762
  2292
        {
dvander@2762
  2293
        int local_offsets[1000];
dvander@2762
  2294
        int local_workspace[1000];
dvander@2762
  2295
        int rc;
dvander@2762
  2296
dvander@2762
  2297
        DPRINTF(("%.*sStarting regex recursion %d\n", rlevel*2-2, SP,
dvander@2762
  2298
          recursing + 1));
dvander@2762
  2299
dvander@2762
  2300
        rc = internal_dfa_exec(
dvander@2762
  2301
          md,                                   /* fixed match data */
dvander@2762
  2302
          start_code + GET(code, 1),            /* this subexpression's code */
dvander@2762
  2303
          ptr,                                  /* where we currently are */
dvander@2762
  2304
          ptr - start_subject,                  /* start offset */
dvander@2762
  2305
          local_offsets,                        /* offset vector */
dvander@2762
  2306
          sizeof(local_offsets)/sizeof(int),    /* size of same */
dvander@2762
  2307
          local_workspace,                      /* workspace vector */
dvander@2762
  2308
          sizeof(local_workspace)/sizeof(int),  /* size of same */
dvander@2762
  2309
          ims,                                  /* the current ims flags */
dvander@2762
  2310
          rlevel,                               /* function recursion level */
dvander@2762
  2311
          recursing + 1);                       /* regex recurse level */
dvander@2762
  2312
dvander@2762
  2313
        DPRINTF(("%.*sReturn from regex recursion %d: rc=%d\n", rlevel*2-2, SP,
dvander@2762
  2314
          recursing + 1, rc));
dvander@2762
  2315
dvander@2762
  2316
        /* Ran out of internal offsets */
dvander@2762
  2317
dvander@2762
  2318
        if (rc == 0) return PCRE_ERROR_DFA_RECURSE;
dvander@2762
  2319
dvander@2762
  2320
        /* For each successful matched substring, set up the next state with a
dvander@2762
  2321
        count of characters to skip before trying it. Note that the count is in
dvander@2762
  2322
        characters, not bytes. */
dvander@2762
  2323
dvander@2762
  2324
        if (rc > 0)
dvander@2762
  2325
          {
dvander@2762
  2326
          for (rc = rc*2 - 2; rc >= 0; rc -= 2)
dvander@2762
  2327
            {
dvander@2762
  2328
            const uschar *p = start_subject + local_offsets[rc];
dvander@2762
  2329
            const uschar *pp = start_subject + local_offsets[rc+1];
dvander@2762
  2330
            int charcount = local_offsets[rc+1] - local_offsets[rc];
dvander@2762
  2331
            while (p < pp) if ((*p++ & 0xc0) == 0x80) charcount--;
dvander@2762
  2332
            if (charcount > 0)
dvander@2762
  2333
              {
dvander@2762
  2334
              ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0, (charcount - 1));
dvander@2762
  2335
              }
dvander@2762
  2336
            else
dvander@2762
  2337
              {
dvander@2762
  2338
              ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0);
dvander@2762
  2339
              }
dvander@2762
  2340
            }
dvander@2762
  2341
          }
dvander@2762
  2342
        else if (rc != PCRE_ERROR_NOMATCH) return rc;
dvander@2762
  2343
        }
dvander@2762
  2344
      break;
dvander@2762
  2345
dvander@2762
  2346
      /*-----------------------------------------------------------------*/
dvander@2762
  2347
      case OP_ONCE:
dvander@2762
  2348
        {
dvander@2762
  2349
        int local_offsets[2];
dvander@2762
  2350
        int local_workspace[1000];
dvander@2762
  2351
dvander@2762
  2352
        int rc = internal_dfa_exec(
dvander@2762
  2353
          md,                                   /* fixed match data */
dvander@2762
  2354
          code,                                 /* this subexpression's code */
dvander@2762
  2355
          ptr,                                  /* where we currently are */
dvander@2762
  2356
          ptr - start_subject,                  /* start offset */
dvander@2762
  2357
          local_offsets,                        /* offset vector */
dvander@2762
  2358
          sizeof(local_offsets)/sizeof(int),    /* size of same */
dvander@2762
  2359
          local_workspace,                      /* workspace vector */
dvander@2762
  2360
          sizeof(local_workspace)/sizeof(int),  /* size of same */
dvander@2762
  2361
          ims,                                  /* the current ims flags */
dvander@2762
  2362
          rlevel,                               /* function recursion level */
dvander@2762
  2363
          recursing);                           /* pass on regex recursion */
dvander@2762
  2364
dvander@2762
  2365
        if (rc >= 0)
dvander@2762
  2366
          {
dvander@2762
  2367
          const uschar *end_subpattern = code;
dvander@2762
  2368
          int charcount = local_offsets[1] - local_offsets[0];
dvander@2762
  2369
          int next_state_offset, repeat_state_offset;
dvander@2762
  2370
dvander@2762
  2371
          do { end_subpattern += GET(end_subpattern, 1); }
dvander@2762
  2372
            while (*end_subpattern == OP_ALT);
dvander@2762
  2373
          next_state_offset = end_subpattern - start_code + LINK_SIZE + 1;
dvander@2762
  2374
dvander@2762
  2375
          /* If the end of this subpattern is KETRMAX or KETRMIN, we must
dvander@2762
  2376
          arrange for the repeat state also to be added to the relevant list.
dvander@2762
  2377
          Calculate the offset, or set -1 for no repeat. */
dvander@2762
  2378
dvander@2762
  2379
          repeat_state_offset = (*end_subpattern == OP_KETRMAX ||
dvander@2762
  2380
                                 *end_subpattern == OP_KETRMIN)?
dvander@2762
  2381
            end_subpattern - start_code - GET(end_subpattern, 1) : -1;
dvander@2762
  2382
dvander@2762
  2383
          /* If we have matched an empty string, add the next state at the
dvander@2762
  2384
          current character pointer. This is important so that the duplicate
dvander@2762
  2385
          checking kicks in, which is what breaks infinite loops that match an
dvander@2762
  2386
          empty string. */
dvander@2762
  2387
dvander@2762
  2388
          if (charcount == 0)
dvander@2762
  2389
            {
dvander@2762
  2390
            ADD_ACTIVE(next_state_offset, 0);
dvander@2762
  2391
            }
dvander@2762
  2392
dvander@2762
  2393
          /* Optimization: if there are no more active states, and there
dvander@2762
  2394
          are no new states yet set up, then skip over the subject string
dvander@2762
  2395
          right here, to save looping. Otherwise, set up the new state to swing
dvander@2762
  2396
          into action when the end of the substring is reached. */
dvander@2762
  2397
dvander@2762
  2398
          else if (i + 1 >= active_count && new_count == 0)
dvander@2762
  2399
            {
dvander@2762
  2400
            ptr += charcount;
dvander@2762
  2401
            clen = 0;
dvander@2762
  2402
            ADD_NEW(next_state_offset, 0);
dvander@2762
  2403
dvander@2762
  2404
            /* If we are adding a repeat state at the new character position,
dvander@2762
  2405
            we must fudge things so that it is the only current state.
dvander@2762
  2406
            Otherwise, it might be a duplicate of one we processed before, and
dvander@2762
  2407
            that would cause it to be skipped. */
dvander@2762
  2408
dvander@2762
  2409
            if (repeat_state_offset >= 0)
dvander@2762
  2410
              {
dvander@2762
  2411
              next_active_state = active_states;
dvander@2762
  2412
              active_count = 0;
dvander@2762
  2413
              i = -1;
dvander@2762
  2414
              ADD_ACTIVE(repeat_state_offset, 0);
dvander@2762
  2415
              }
dvander@2762
  2416
            }
dvander@2762
  2417
          else
dvander@2762
  2418
            {
dvander@2762
  2419
            const uschar *p = start_subject + local_offsets[0];
dvander@2762
  2420
            const uschar *pp = start_subject + local_offsets[1];
dvander@2762
  2421
            while (p < pp) if ((*p++ & 0xc0) == 0x80) charcount--;
dvander@2762
  2422
            ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1));
dvander@2762
  2423
            if (repeat_state_offset >= 0)
dvander@2762
  2424
              { ADD_NEW_DATA(-repeat_state_offset, 0, (charcount - 1)); }
dvander@2762
  2425
            }
dvander@2762
  2426
dvander@2762
  2427
          }
dvander@2762
  2428
        else if (rc != PCRE_ERROR_NOMATCH) return rc;
dvander@2762
  2429
        }
dvander@2762
  2430
      break;
dvander@2762
  2431
dvander@2762
  2432
dvander@2762
  2433
/* ========================================================================== */
dvander@2762
  2434
      /* Handle callouts */
dvander@2762
  2435
dvander@2762
  2436
      case OP_CALLOUT:
dvander@2762
  2437
      rrc = 0;
dvander@2762
  2438
      if (pcre_callout != NULL)
dvander@2762
  2439
        {
dvander@2762
  2440
        pcre_callout_block cb;
dvander@2762
  2441
        cb.version          = 1;   /* Version 1 of the callout block */
dvander@2762
  2442
        cb.callout_number   = code[1];
dvander@2762
  2443
        cb.offset_vector    = offsets;
dvander@2762
  2444
        cb.subject          = (PCRE_SPTR)start_subject;
dvander@2762
  2445
        cb.subject_length   = end_subject - start_subject;
dvander@2762
  2446
        cb.start_match      = current_subject - start_subject;
dvander@2762
  2447
        cb.current_position = ptr - start_subject;
dvander@2762
  2448
        cb.pattern_position = GET(code, 2);
dvander@2762
  2449
        cb.next_item_length = GET(code, 2 + LINK_SIZE);
dvander@2762
  2450
        cb.capture_top      = 1;
dvander@2762
  2451
        cb.capture_last     = -1;
dvander@2762
  2452
        cb.callout_data     = md->callout_data;
dvander@2762
  2453
        if ((rrc = (*pcre_callout)(&cb)) < 0) return rrc;   /* Abandon */
dvander@2762
  2454
        }
dvander@2762
  2455
      if (rrc == 0)
dvander@2762
  2456
        { ADD_ACTIVE(state_offset + _pcre_OP_lengths[OP_CALLOUT], 0); }
dvander@2762
  2457
      break;
dvander@2762
  2458
dvander@2762
  2459
dvander@2762
  2460
/* ========================================================================== */
dvander@2762
  2461
      default:        /* Unsupported opcode */
dvander@2762
  2462
      return PCRE_ERROR_DFA_UITEM;
dvander@2762
  2463
      }
dvander@2762
  2464
dvander@2762
  2465
    NEXT_ACTIVE_STATE: continue;
dvander@2762
  2466
dvander@2762
  2467
    }      /* End of loop scanning active states */
dvander@2762
  2468
dvander@2762
  2469
  /* We have finished the processing at the current subject character. If no
dvander@2762
  2470
  new states have been set for the next character, we have found all the
dvander@2762
  2471
  matches that we are going to find. If we are at the top level and partial
dvander@2762
  2472
  matching has been requested, check for appropriate conditions. */
dvander@2762
  2473
dvander@2762
  2474
  if (new_count <= 0)
dvander@2762
  2475
    {
dvander@2762
  2476
    if (match_count < 0 &&                     /* No matches found */
dvander@2762
  2477
        rlevel == 1 &&                         /* Top level match function */
dvander@2762
  2478
        (md->moptions & PCRE_PARTIAL) != 0 &&  /* Want partial matching */
dvander@2762
  2479
        ptr >= end_subject &&                  /* Reached end of subject */
dvander@2762
  2480
        ptr > current_subject)                 /* Matched non-empty string */
dvander@2762
  2481
      {
dvander@2762
  2482
      if (offsetcount >= 2)
dvander@2762
  2483
        {
dvander@2762
  2484
        offsets[0] = current_subject - start_subject;
dvander@2762
  2485
        offsets[1] = end_subject - start_subject;
dvander@2762
  2486
        }
dvander@2762
  2487
      match_count = PCRE_ERROR_PARTIAL;
dvander@2762
  2488
      }
dvander@2762
  2489
dvander@2762
  2490
    DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n"
dvander@2762
  2491
      "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count,
dvander@2762
  2492
      rlevel*2-2, SP));
dvander@2762
  2493
    break;        /* In effect, "return", but see the comment below */
dvander@2762
  2494
    }
dvander@2762
  2495
dvander@2762
  2496
  /* One or more states are active for the next character. */
dvander@2762
  2497
dvander@2762
  2498
  ptr += clen;    /* Advance to next subject character */
dvander@2762
  2499
  }               /* Loop to move along the subject string */
dvander@2762
  2500
dvander@2762
  2501
/* Control gets here from "break" a few lines above. We do it this way because
dvander@2762
  2502
if we use "return" above, we have compiler trouble. Some compilers warn if
dvander@2762
  2503
there's nothing here because they think the function doesn't return a value. On
dvander@2762
  2504
the other hand, if we put a dummy statement here, some more clever compilers
dvander@2762
  2505
complain that it can't be reached. Sigh. */
dvander@2762
  2506
dvander@2762
  2507
return match_count;
dvander@2762
  2508
}
dvander@2762
  2509
dvander@2762
  2510
dvander@2762
  2511
dvander@2762
  2512
dvander@2762
  2513
/*************************************************
dvander@2762
  2514
*    Execute a Regular Expression - DFA engine   *
dvander@2762
  2515
*************************************************/
dvander@2762
  2516
dvander@2762
  2517
/* This external function applies a compiled re to a subject string using a DFA
dvander@2762
  2518
engine. This function calls the internal function multiple times if the pattern
dvander@2762
  2519
is not anchored.
dvander@2762
  2520
dvander@2762
  2521
Arguments:
dvander@2762
  2522
  argument_re     points to the compiled expression
dvander@2762
  2523
  extra_data      points to extra data or is NULL
dvander@2762
  2524
  subject         points to the subject string
dvander@2762
  2525
  length          length of subject string (may contain binary zeros)
dvander@2762
  2526
  start_offset    where to start in the subject string
dvander@2762
  2527
  options         option bits
dvander@2762
  2528
  offsets         vector of match offsets
dvander@2762
  2529
  offsetcount     size of same
dvander@2762
  2530
  workspace       workspace vector
dvander@2762
  2531
  wscount         size of same
dvander@2762
  2532
dvander@2762
  2533
Returns:          > 0 => number of match offset pairs placed in offsets
dvander@2762
  2534
                  = 0 => offsets overflowed; longest matches are present
dvander@2762
  2535
                   -1 => failed to match
dvander@2762
  2536
                 < -1 => some kind of unexpected problem
dvander@2762
  2537
*/
dvander@2762
  2538
dvander@2762
  2539
PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
dvander@2762
  2540
pcre_dfa_exec(const pcre *argument_re, const pcre_extra *extra_data,
dvander@2762
  2541
  const char *subject, int length, int start_offset, int options, int *offsets,
dvander@2762
  2542
  int offsetcount, int *workspace, int wscount)
dvander@2762
  2543
{
dvander@2762
  2544
real_pcre *re = (real_pcre *)argument_re;
dvander@2762
  2545
dfa_match_data match_block;
dvander@2762
  2546
dfa_match_data *md = &match_block;
dvander@2762
  2547
BOOL utf8, anchored, startline, firstline;
dvander@2762
  2548
const uschar *current_subject, *end_subject, *lcc;
dvander@2762
  2549
dvander@2762
  2550
pcre_study_data internal_study;
dvander@2762
  2551
const pcre_study_data *study = NULL;
dvander@2762
  2552
real_pcre internal_re;
dvander@2762
  2553
dvander@2762
  2554
const uschar *req_byte_ptr;
dvander@2762
  2555
const uschar *start_bits = NULL;
dvander@2762
  2556
BOOL first_byte_caseless = FALSE;
dvander@2762
  2557
BOOL req_byte_caseless = FALSE;
dvander@2762
  2558
int first_byte = -1;
dvander@2762
  2559
int req_byte = -1;
dvander@2762
  2560
int req_byte2 = -1;
dvander@2762
  2561
int newline;
dvander@2762
  2562
dvander@2762
  2563
/* Plausibility checks */
dvander@2762
  2564
dvander@2762
  2565
if ((options & ~PUBLIC_DFA_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
dvander@2762
  2566
if (re == NULL || subject == NULL || workspace == NULL ||
dvander@2762
  2567
   (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
dvander@2762
  2568
if (offsetcount < 0) return PCRE_ERROR_BADCOUNT;
dvander@2762
  2569
if (wscount < 20) return PCRE_ERROR_DFA_WSSIZE;
dvander@2762
  2570
dvander@2762
  2571
/* We need to find the pointer to any study data before we test for byte
dvander@2762
  2572
flipping, so we scan the extra_data block first. This may set two fields in the
dvander@2762
  2573
match block, so we must initialize them beforehand. However, the other fields
dvander@2762
  2574
in the match block must not be set until after the byte flipping. */
dvander@2762
  2575
dvander@2762
  2576
md->tables = re->tables;
dvander@2762
  2577
md->callout_data = NULL;
dvander@2762
  2578
dvander@2762
  2579
if (extra_data != NULL)
dvander@2762
  2580
  {
dvander@2762
  2581
  unsigned int flags = extra_data->flags;
dvander@2762
  2582
  if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
dvander@2762
  2583
    study = (const pcre_study_data *)extra_data->study_data;
dvander@2762
  2584
  if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) return PCRE_ERROR_DFA_UMLIMIT;
dvander@2762
  2585
  if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0)
dvander@2762
  2586
    return PCRE_ERROR_DFA_UMLIMIT;
dvander@2762
  2587
  if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
dvander@2762
  2588
    md->callout_data = extra_data->callout_data;
dvander@2762
  2589
  if ((flags & PCRE_EXTRA_TABLES) != 0)
dvander@2762
  2590
    md->tables = extra_data->tables;
dvander@2762
  2591
  }
dvander@2762
  2592
dvander@2762
  2593
/* Check that the first field in the block is the magic number. If it is not,
dvander@2762
  2594
test for a regex that was compiled on a host of opposite endianness. If this is
dvander@2762
  2595
the case, flipped values are put in internal_re and internal_study if there was
dvander@2762
  2596
study data too. */
dvander@2762
  2597
dvander@2762
  2598
if (re->magic_number != MAGIC_NUMBER)
dvander@2762
  2599
  {
dvander@2762
  2600
  re = _pcre_try_flipped(re, &internal_re, study, &internal_study);
dvander@2762
  2601
  if (re == NULL) return PCRE_ERROR_BADMAGIC;
dvander@2762
  2602
  if (study != NULL) study = &internal_study;
dvander@2762
  2603
  }
dvander@2762
  2604
dvander@2762
  2605
/* Set some local values */
dvander@2762
  2606
dvander@2762
  2607
current_subject = (const unsigned char *)subject + start_offset;
dvander@2762
  2608
end_subject = (const unsigned char *)subject + length;
dvander@2762
  2609
req_byte_ptr = current_subject - 1;
dvander@2762
  2610
dvander@2762
  2611
#ifdef SUPPORT_UTF8
dvander@2762
  2612
utf8 = (re->options & PCRE_UTF8) != 0;
dvander@2762
  2613
#else
dvander@2762
  2614
utf8 = FALSE;
dvander@2762
  2615
#endif
dvander@2762
  2616
dvander@2762
  2617
anchored = (options & (PCRE_ANCHORED|PCRE_DFA_RESTART)) != 0 ||
dvander@2762
  2618
  (re->options & PCRE_ANCHORED) != 0;
dvander@2762
  2619
dvander@2762
  2620
/* The remaining fixed data for passing around. */
dvander@2762
  2621
dvander@2762
  2622
md->start_code = (const uschar *)argument_re +
dvander@2762
  2623
    re->name_table_offset + re->name_count * re->name_entry_size;
dvander@2762
  2624
md->start_subject = (const unsigned char *)subject;
dvander@2762
  2625
md->end_subject = end_subject;
dvander@2762
  2626
md->moptions = options;
dvander@2762
  2627
md->poptions = re->options;
dvander@2762
  2628
dvander@2762
  2629
/* If the BSR option is not set at match time, copy what was set
dvander@2762
  2630
at compile time. */
dvander@2762
  2631
dvander@2762
  2632
if ((md->moptions & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) == 0)
dvander@2762
  2633
  {
dvander@2762
  2634
  if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0)
dvander@2762
  2635
    md->moptions |= re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE);
dvander@2762
  2636
#ifdef BSR_ANYCRLF
dvander@2762
  2637
  else md->moptions |= PCRE_BSR_ANYCRLF;
dvander@2762
  2638
#endif
dvander@2762
  2639
  }
dvander@2762
  2640
dvander@2762
  2641
/* Handle different types of newline. The three bits give eight cases. If
dvander@2762
  2642
nothing is set at run time, whatever was used at compile time applies. */
dvander@2762
  2643
dvander@2762
  2644
switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) &
dvander@2762
  2645
         PCRE_NEWLINE_BITS)
dvander@2762
  2646
  {
dvander@2762
  2647
  case 0: newline = NEWLINE; break;   /* Compile-time default */
dvander@2762
  2648
  case PCRE_NEWLINE_CR: newline = CHAR_CR; break;
dvander@2762
  2649
  case PCRE_NEWLINE_LF: newline = CHAR_NL; break;
dvander@2762
  2650
  case PCRE_NEWLINE_CR+
dvander@2762
  2651
       PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break;
dvander@2762
  2652
  case PCRE_NEWLINE_ANY: newline = -1; break;
dvander@2762
  2653
  case PCRE_NEWLINE_ANYCRLF: newline = -2; break;
dvander@2762
  2654
  default: return PCRE_ERROR_BADNEWLINE;
dvander@2762
  2655
  }
dvander@2762
  2656
dvander@2762
  2657
if (newline == -2)
dvander@2762
  2658
  {
dvander@2762
  2659
  md->nltype = NLTYPE_ANYCRLF;
dvander@2762
  2660
  }
dvander@2762
  2661
else if (newline < 0)
dvander@2762
  2662
  {
dvander@2762
  2663
  md->nltype = NLTYPE_ANY;
dvander@2762
  2664
  }
dvander@2762
  2665
else
dvander@2762
  2666
  {
dvander@2762
  2667
  md->nltype = NLTYPE_FIXED;
dvander@2762
  2668
  if (newline > 255)
dvander@2762
  2669
    {
dvander@2762
  2670
    md->nllen = 2;
dvander@2762
  2671
    md->nl[0] = (newline >> 8) & 255;
dvander@2762
  2672
    md->nl[1] = newline & 255;
dvander@2762
  2673
    }
dvander@2762
  2674
  else
dvander@2762
  2675
    {
dvander@2762
  2676
    md->nllen = 1;
dvander@2762
  2677
    md->nl[0] = newline;
dvander@2762
  2678
    }
dvander@2762
  2679
  }
dvander@2762
  2680
dvander@2762
  2681
/* Check a UTF-8 string if required. Unfortunately there's no way of passing
dvander@2762
  2682
back the character offset. */
dvander@2762
  2683
dvander@2762
  2684
#ifdef SUPPORT_UTF8
dvander@2762
  2685
if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0)
dvander@2762
  2686
  {
dvander@2762
  2687
  if (_pcre_valid_utf8((uschar *)subject, length) >= 0)
dvander@2762
  2688
    return PCRE_ERROR_BADUTF8;
dvander@2762
  2689
  if (start_offset > 0 && start_offset < length)
dvander@2762
  2690
    {
dvander@2762
  2691
    int tb = ((uschar *)subject)[start_offset];
dvander@2762
  2692
    if (tb > 127)
dvander@2762
  2693
      {
dvander@2762
  2694
      tb &= 0xc0;
dvander@2762
  2695
      if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET;
dvander@2762
  2696
      }
dvander@2762
  2697
    }
dvander@2762
  2698
  }
dvander@2762
  2699
#endif
dvander@2762
  2700
dvander@2762
  2701
/* If the exec call supplied NULL for tables, use the inbuilt ones. This
dvander@2762
  2702
is a feature that makes it possible to save compiled regex and re-use them
dvander@2762
  2703
in other programs later. */
dvander@2762
  2704
dvander@2762
  2705
if (md->tables == NULL) md->tables = _pcre_default_tables;
dvander@2762
  2706
dvander@2762
  2707
/* The lower casing table and the "must be at the start of a line" flag are
dvander@2762
  2708
used in a loop when finding where to start. */
dvander@2762
  2709
dvander@2762
  2710
lcc = md->tables + lcc_offset;
dvander@2762
  2711
startline = (re->flags & PCRE_STARTLINE) != 0;
dvander@2762
  2712
firstline = (re->options & PCRE_FIRSTLINE) != 0;
dvander@2762
  2713
dvander@2762
  2714
/* Set up the first character to match, if available. The first_byte value is
dvander@2762
  2715
never set for an anchored regular expression, but the anchoring may be forced
dvander@2762
  2716
at run time, so we have to test for anchoring. The first char may be unset for
dvander@2762
  2717
an unanchored pattern, of course. If there's no first char and the pattern was
dvander@2762
  2718
studied, there may be a bitmap of possible first characters. */
dvander@2762
  2719
dvander@2762
  2720
if (!anchored)
dvander@2762
  2721
  {
dvander@2762
  2722
  if ((re->flags & PCRE_FIRSTSET) != 0)
dvander@2762
  2723
    {
dvander@2762
  2724
    first_byte = re->first_byte & 255;
dvander@2762
  2725
    if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE)
dvander@2762
  2726
      first_byte = lcc[first_byte];
dvander@2762
  2727
    }
dvander@2762
  2728
  else
dvander@2762
  2729
    {
dvander@2762
  2730
    if (startline && study != NULL &&
dvander@2762
  2731
         (study->options & PCRE_STUDY_MAPPED) != 0)
dvander@2762
  2732
      start_bits = study->start_bits;
dvander@2762
  2733
    }
dvander@2762
  2734
  }
dvander@2762
  2735
dvander@2762
  2736
/* For anchored or unanchored matches, there may be a "last known required
dvander@2762
  2737
character" set. */
dvander@2762
  2738
dvander@2762
  2739
if ((re->flags & PCRE_REQCHSET) != 0)
dvander@2762
  2740
  {
dvander@2762
  2741
  req_byte = re->req_byte & 255;
dvander@2762
  2742
  req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0;
dvander@2762
  2743
  req_byte2 = (md->tables + fcc_offset)[req_byte];  /* case flipped */
dvander@2762
  2744
  }
dvander@2762
  2745
dvander@2762
  2746
/* Call the main matching function, looping for a non-anchored regex after a
dvander@2762
  2747
failed match. If not restarting, perform certain optimizations at the start of
dvander@2762
  2748
a match. */
dvander@2762
  2749
dvander@2762
  2750
for (;;)
dvander@2762
  2751
  {
dvander@2762
  2752
  int rc;
dvander@2762
  2753
dvander@2762
  2754
  if ((options & PCRE_DFA_RESTART) == 0)
dvander@2762
  2755
    {
dvander@2762
  2756
    const uschar *save_end_subject = end_subject;
dvander@2762
  2757
dvander@2762
  2758
    /* If firstline is TRUE, the start of the match is constrained to the first
dvander@2762
  2759
    line of a multiline string. Implement this by temporarily adjusting
dvander@2762
  2760
    end_subject so that we stop scanning at a newline. If the match fails at
dvander@2762
  2761
    the newline, later code breaks this loop. */
dvander@2762
  2762
dvander@2762
  2763
    if (firstline)
dvander@2762
  2764
      {
dvander@2762
  2765
      USPTR t = current_subject;
dvander@2762
  2766
#ifdef SUPPORT_UTF8
dvander@2762
  2767
      if (utf8)
dvander@2762
  2768
        {
dvander@2762
  2769
        while (t < md->end_subject && !IS_NEWLINE(t))
dvander@2762
  2770
          {
dvander@2762
  2771
          t++;
dvander@2762
  2772
          while (t < end_subject && (*t & 0xc0) == 0x80) t++;
dvander@2762
  2773
          }
dvander@2762
  2774
        }
dvander@2762
  2775
      else
dvander@2762
  2776
#endif
dvander@2762
  2777
      while (t < md->end_subject && !IS_NEWLINE(t)) t++;
dvander@2762
  2778
      end_subject = t;
dvander@2762
  2779
      }
dvander@2762
  2780
dvander@2762
  2781
    /* There are some optimizations that avoid running the match if a known
dvander@2762
  2782
    starting point is not found, or if a known later character is not present.
dvander@2762
  2783
    However, there is an option that disables these, for testing and for
dvander@2762
  2784
    ensuring that all callouts do actually occur. */
dvander@2762
  2785
dvander@2762
  2786
    if ((options & PCRE_NO_START_OPTIMIZE) == 0)
dvander@2762
  2787
      {
dvander@2762
  2788
dvander@2762
  2789
      /* Advance to a known first byte. */
dvander@2762
  2790
dvander@2762
  2791
      if (first_byte >= 0)
dvander@2762
  2792
        {
dvander@2762
  2793
        if (first_byte_caseless)
dvander@2762
  2794
          while (current_subject < end_subject &&
dvander@2762
  2795
                 lcc[*current_subject] != first_byte)
dvander@2762
  2796
            current_subject++;
dvander@2762
  2797
        else
dvander@2762
  2798
          while (current_subject < end_subject &&
dvander@2762
  2799
                 *current_subject != first_byte)
dvander@2762
  2800
            current_subject++;
dvander@2762
  2801
        }
dvander@2762
  2802
dvander@2762
  2803
      /* Or to just after a linebreak for a multiline match if possible */
dvander@2762
  2804
dvander@2762
  2805
      else if (startline)
dvander@2762
  2806
        {
dvander@2762
  2807
        if (current_subject > md->start_subject + start_offset)
dvander@2762
  2808
          {
dvander@2762
  2809
#ifdef SUPPORT_UTF8
dvander@2762
  2810
          if (utf8)
dvander@2762
  2811
            {
dvander@2762
  2812
            while (current_subject < end_subject &&
dvander@2762
  2813
                   !WAS_NEWLINE(current_subject))
dvander@2762
  2814
              {
dvander@2762
  2815
              current_subject++;
dvander@2762
  2816
              while(current_subject < end_subject &&
dvander@2762
  2817
                    (*current_subject & 0xc0) == 0x80)
dvander@2762
  2818
                current_subject++;
dvander@2762
  2819
              }
dvander@2762
  2820
            }
dvander@2762
  2821
          else
dvander@2762
  2822
#endif
dvander@2762
  2823
          while (current_subject < end_subject && !WAS_NEWLINE(current_subject))
dvander@2762
  2824
            current_subject++;
dvander@2762
  2825
dvander@2762
  2826
          /* If we have just passed a CR and the newline option is ANY or
dvander@2762
  2827
          ANYCRLF, and we are now at a LF, advance the match position by one
dvander@2762
  2828
          more character. */
dvander@2762
  2829
dvander@2762
  2830
          if (current_subject[-1] == CHAR_CR &&
dvander@2762
  2831
               (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) &&
dvander@2762
  2832
               current_subject < end_subject &&
dvander@2762
  2833
               *current_subject == CHAR_NL)
dvander@2762
  2834
            current_subject++;
dvander@2762
  2835
          }
dvander@2762
  2836
        }
dvander@2762
  2837
dvander@2762
  2838
      /* Or to a non-unique first char after study */
dvander@2762
  2839
dvander@2762
  2840
      else if (start_bits != NULL)
dvander@2762
  2841
        {
dvander@2762
  2842
        while (current_subject < end_subject)
dvander@2762
  2843
          {
dvander@2762
  2844
          register unsigned int c = *current_subject;
dvander@2762
  2845
          if ((start_bits[c/8] & (1 << (c&7))) == 0) current_subject++;
dvander@2762
  2846
            else break;
dvander@2762
  2847
          }
dvander@2762
  2848
        }
dvander@2762
  2849
      }
dvander@2762
  2850
dvander@2762
  2851
    /* Restore fudged end_subject */
dvander@2762
  2852
dvander@2762
  2853
    end_subject = save_end_subject;
dvander@2762
  2854
    }
dvander@2762
  2855
dvander@2762
  2856
  /* If req_byte is set, we know that that character must appear in the subject
dvander@2762
  2857
  for the match to succeed. If the first character is set, req_byte must be
dvander@2762
  2858
  later in the subject; otherwise the test starts at the match point. This
dvander@2762
  2859
  optimization can save a huge amount of work in patterns with nested unlimited
dvander@2762
  2860
  repeats that aren't going to match. Writing separate code for cased/caseless
dvander@2762
  2861
  versions makes it go faster, as does using an autoincrement and backing off
dvander@2762
  2862
  on a match.
dvander@2762
  2863
dvander@2762
  2864
  HOWEVER: when the subject string is very, very long, searching to its end can
dvander@2762
  2865
  take a long time, and give bad performance on quite ordinary patterns. This
dvander@2762
  2866
  showed up when somebody was matching /^C/ on a 32-megabyte string... so we
dvander@2762
  2867
  don't do this when the string is sufficiently long.
dvander@2762
  2868
dvander@2762
  2869
  ALSO: this processing is disabled when partial matching is requested, and can
dvander@2762
  2870
  also be explicitly deactivated. */
dvander@2762
  2871
dvander@2762
  2872
  if ((options & PCRE_NO_START_OPTIMIZE) == 0 &&
dvander@2762
  2873
      req_byte >= 0 &&
dvander@2762
  2874
      end_subject - current_subject < REQ_BYTE_MAX &&
dvander@2762
  2875
      (options & PCRE_PARTIAL) == 0)
dvander@2762
  2876
    {
dvander@2762
  2877
    register const uschar *p = current_subject + ((first_byte >= 0)? 1 : 0);
dvander@2762
  2878
dvander@2762
  2879
    /* We don't need to repeat the search if we haven't yet reached the
dvander@2762
  2880
    place we found it at last time. */
dvander@2762
  2881
dvander@2762
  2882
    if (p > req_byte_ptr)
dvander@2762
  2883
      {
dvander@2762
  2884
      if (req_byte_caseless)
dvander@2762
  2885
        {
dvander@2762
  2886
        while (p < end_subject)
dvander@2762
  2887
          {
dvander@2762
  2888
          register int pp = *p++;
dvander@2762
  2889
          if (pp == req_byte || pp == req_byte2) { p--; break; }
dvander@2762
  2890
          }
dvander@2762
  2891
        }
dvander@2762
  2892
      else
dvander@2762
  2893
        {
dvander@2762
  2894
        while (p < end_subject)
dvander@2762
  2895
          {
dvander@2762
  2896
          if (*p++ == req_byte) { p--; break; }
dvander@2762
  2897
          }
dvander@2762
  2898
        }
dvander@2762
  2899
dvander@2762
  2900
      /* If we can't find the required character, break the matching loop,
dvander@2762
  2901
      which will cause a return or PCRE_ERROR_NOMATCH. */
dvander@2762
  2902
dvander@2762
  2903
      if (p >= end_subject) break;
dvander@2762
  2904
dvander@2762
  2905
      /* If we have found the required character, save the point where we
dvander@2762
  2906
      found it, so that we don't search again next time round the loop if
dvander@2762
  2907
      the start hasn't passed this character yet. */
dvander@2762
  2908
dvander@2762
  2909
      req_byte_ptr = p;
dvander@2762
  2910
      }
dvander@2762
  2911
    }
dvander@2762
  2912
dvander@2762
  2913
  /* OK, now we can do the business */
dvander@2762
  2914
dvander@2762
  2915
  rc = internal_dfa_exec(
dvander@2762
  2916
    md,                                /* fixed match data */
dvander@2762
  2917
    md->start_code,                    /* this subexpression's code */
dvander@2762
  2918
    current_subject,                   /* where we currently are */
dvander@2762
  2919
    start_offset,                      /* start offset in subject */
dvander@2762
  2920
    offsets,                           /* offset vector */
dvander@2762
  2921
    offsetcount,                       /* size of same */
dvander@2762
  2922
    workspace,                         /* workspace vector */
dvander@2762
  2923
    wscount,                           /* size of same */
dvander@2762
  2924
    re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL), /* ims flags */
dvander@2762
  2925
    0,                                 /* function recurse level */
dvander@2762
  2926
    0);                                /* regex recurse level */
dvander@2762
  2927
dvander@2762
  2928
  /* Anything other than "no match" means we are done, always; otherwise, carry
dvander@2762
  2929
  on only if not anchored. */
dvander@2762
  2930
dvander@2762
  2931
  if (rc != PCRE_ERROR_NOMATCH || anchored) return rc;
dvander@2762
  2932
dvander@2762
  2933
  /* Advance to the next subject character unless we are at the end of a line
dvander@2762
  2934
  and firstline is set. */
dvander@2762
  2935
dvander@2762
  2936
  if (firstline && IS_NEWLINE(current_subject)) break;
dvander@2762
  2937
  current_subject++;
dvander@2762
  2938
  if (utf8)
dvander@2762
  2939
    {
dvander@2762
  2940
    while (current_subject < end_subject && (*current_subject & 0xc0) == 0x80)
dvander@2762
  2941
      current_subject++;
dvander@2762
  2942
    }
dvander@2762
  2943
  if (current_subject > end_subject) break;
dvander@2762
  2944
dvander@2762
  2945
  /* If we have just passed a CR and we are now at a LF, and the pattern does
dvander@2762
  2946
  not contain any explicit matches for \r or \n, and the newline option is CRLF
dvander@2762
  2947
  or ANY or ANYCRLF, advance the match position by one more character. */
dvander@2762
  2948
dvander@2762
  2949
  if (current_subject[-1] == CHAR_CR &&
dvander@2762
  2950
      current_subject < end_subject &&
dvander@2762
  2951
      *current_subject == CHAR_NL &&
dvander@2762
  2952
      (re->flags & PCRE_HASCRORLF) == 0 &&
dvander@2762
  2953
        (md->nltype == NLTYPE_ANY ||
dvander@2762
  2954
         md->nltype == NLTYPE_ANYCRLF ||
dvander@2762
  2955
         md->nllen == 2))
dvander@2762
  2956
    current_subject++;
dvander@2762
  2957
dvander@2762
  2958
  }   /* "Bumpalong" loop */
dvander@2762
  2959
dvander@2762
  2960
return PCRE_ERROR_NOMATCH;
dvander@2762
  2961
}
dvander@2762
  2962
dvander@2762
  2963
/* End of pcre_dfa_exec.c */