Blame win32/regexec.c

Packit Service ff689b
/*
Packit Service ff689b
  regexec.c - TRE POSIX compatible matching functions (and more).
Packit Service ff689b
Packit Service ff689b
  Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi>
Packit Service ff689b
  All rights reserved.
Packit Service ff689b
Packit Service ff689b
  Redistribution and use in source and binary forms, with or without
Packit Service ff689b
  modification, are permitted provided that the following conditions
Packit Service ff689b
  are met:
Packit Service ff689b
Packit Service ff689b
    1. Redistributions of source code must retain the above copyright
Packit Service ff689b
       notice, this list of conditions and the following disclaimer.
Packit Service ff689b
Packit Service ff689b
    2. Redistributions in binary form must reproduce the above copyright
Packit Service ff689b
       notice, this list of conditions and the following disclaimer in the
Packit Service ff689b
       documentation and/or other materials provided with the distribution.
Packit Service ff689b
Packit Service ff689b
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
Packit Service ff689b
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit Service ff689b
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit Service ff689b
  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
Packit Service ff689b
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit Service ff689b
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit Service ff689b
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit Service ff689b
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit Service ff689b
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service ff689b
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit Service ff689b
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service ff689b
Packit Service ff689b
*/
Packit Service ff689b
Packit Service ff689b
#include <stdlib.h>
Packit Service ff689b
#include <string.h>
Packit Service ff689b
#include <wchar.h>
Packit Service ff689b
#include <wctype.h>
Packit Service ff689b
#include <limits.h>
Packit Service ff689b
#include <stdint.h>
Packit Service ff689b
Packit Service ff689b
#include <regex.h>
Packit Service ff689b
Packit Service ff689b
#include "tre.h"
Packit Service ff689b
Packit Service ff689b
#include <assert.h>
Packit Service ff689b
Packit Service ff689b
static void
Packit Service ff689b
tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
Packit Service ff689b
    const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo);
Packit Service ff689b
Packit Service ff689b
/***********************************************************************
Packit Service ff689b
 from tre-match-utils.h
Packit Service ff689b
***********************************************************************/
Packit Service ff689b
Packit Service ff689b
#define GET_NEXT_WCHAR() do {                                                 \
Packit Service ff689b
    prev_c = next_c; pos += pos_add_next;                                     \
Packit Service ff689b
    if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) {        \
Packit Service ff689b
        if (pos_add_next < 0) { ret = REG_NOMATCH; goto error_exit; }         \
Packit Service ff689b
        else pos_add_next++;                                                  \
Packit Service ff689b
    }                                                                         \
Packit Service ff689b
    str_byte += pos_add_next;                                                 \
Packit Service ff689b
  } while (0)
Packit Service ff689b
Packit Service ff689b
#define IS_WORD_CHAR(c)  ((c) == L'_' || tre_isalnum(c))
Packit Service ff689b
Packit Service ff689b
#define CHECK_ASSERTIONS(assertions)                \
Packit Service ff689b
  (((assertions & ASSERT_AT_BOL)                \
Packit Service ff689b
    && (pos > 0 || reg_notbol)                  \
Packit Service ff689b
    && (prev_c != L'\n' || !reg_newline))             \
Packit Service ff689b
   || ((assertions & ASSERT_AT_EOL)               \
Packit Service ff689b
       && (next_c != L'\0' || reg_noteol)             \
Packit Service ff689b
       && (next_c != L'\n' || !reg_newline))              \
Packit Service ff689b
   || ((assertions & ASSERT_AT_BOW)               \
Packit Service ff689b
       && (IS_WORD_CHAR(prev_c) || !IS_WORD_CHAR(next_c)))                \
Packit Service ff689b
   || ((assertions & ASSERT_AT_EOW)               \
Packit Service ff689b
       && (!IS_WORD_CHAR(prev_c) || IS_WORD_CHAR(next_c)))          \
Packit Service ff689b
   || ((assertions & ASSERT_AT_WB)                \
Packit Service ff689b
       && (pos != 0 && next_c != L'\0'                \
Packit Service ff689b
     && IS_WORD_CHAR(prev_c) == IS_WORD_CHAR(next_c)))          \
Packit Service ff689b
   || ((assertions & ASSERT_AT_WB_NEG)                \
Packit Service ff689b
       && (pos == 0 || next_c == L'\0'                \
Packit Service ff689b
     || IS_WORD_CHAR(prev_c) != IS_WORD_CHAR(next_c))))
Packit Service ff689b
Packit Service ff689b
#define CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)                             \
Packit Service ff689b
  (((trans_i->assertions & ASSERT_CHAR_CLASS)                                 \
Packit Service ff689b
       && !(tnfa->cflags & REG_ICASE)                                         \
Packit Service ff689b
       && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class))                 \
Packit Service ff689b
    || ((trans_i->assertions & ASSERT_CHAR_CLASS)                             \
Packit Service ff689b
        && (tnfa->cflags & REG_ICASE)                                         \
Packit Service ff689b
        && !tre_isctype(tre_tolower((tre_cint_t)prev_c),trans_i->u.class)     \
Packit Service ff689b
  && !tre_isctype(tre_toupper((tre_cint_t)prev_c),trans_i->u.class))    \
Packit Service ff689b
    || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG)                         \
Packit Service ff689b
        && tre_neg_char_classes_match(trans_i->neg_classes,(tre_cint_t)prev_c,\
Packit Service ff689b
                                      tnfa->cflags & REG_ICASE)))
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
/* Returns 1 if `t1' wins `t2', 0 otherwise. */
Packit Service ff689b
static int
Packit Service ff689b
tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions,
Packit Service ff689b
        regoff_t *t1, regoff_t *t2)
Packit Service ff689b
{
Packit Service ff689b
  int i;
Packit Service ff689b
  for (i = 0; i < num_tags; i++)
Packit Service ff689b
    {
Packit Service ff689b
      if (tag_directions[i] == TRE_TAG_MINIMIZE)
Packit Service ff689b
  {
Packit Service ff689b
    if (t1[i] < t2[i])
Packit Service ff689b
      return 1;
Packit Service ff689b
    if (t1[i] > t2[i])
Packit Service ff689b
      return 0;
Packit Service ff689b
  }
Packit Service ff689b
      else
Packit Service ff689b
  {
Packit Service ff689b
    if (t1[i] > t2[i])
Packit Service ff689b
      return 1;
Packit Service ff689b
    if (t1[i] < t2[i])
Packit Service ff689b
      return 0;
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
  /*  assert(0);*/
Packit Service ff689b
  return 0;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
static int
Packit Service ff689b
tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase)
Packit Service ff689b
{
Packit Service ff689b
  while (*classes != (tre_ctype_t)0)
Packit Service ff689b
    if ((!icase && tre_isctype(wc, *classes))
Packit Service ff689b
  || (icase && (tre_isctype(tre_toupper(wc), *classes)
Packit Service ff689b
          || tre_isctype(tre_tolower(wc), *classes))))
Packit Service ff689b
      return 1; /* Match. */
Packit Service ff689b
    else
Packit Service ff689b
      classes++;
Packit Service ff689b
  return 0; /* No match. */
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
/***********************************************************************
Packit Service ff689b
 from tre-match-parallel.c
Packit Service ff689b
***********************************************************************/
Packit Service ff689b
Packit Service ff689b
/*
Packit Service ff689b
  This algorithm searches for matches basically by reading characters
Packit Service ff689b
  in the searched string one by one, starting at the beginning.  All
Packit Service ff689b
  matching paths in the TNFA are traversed in parallel.  When two or
Packit Service ff689b
  more paths reach the same state, exactly one is chosen according to
Packit Service ff689b
  tag ordering rules; if returning submatches is not required it does
Packit Service ff689b
  not matter which path is chosen.
Packit Service ff689b
Packit Service ff689b
  The worst case time required for finding the leftmost and longest
Packit Service ff689b
  match, or determining that there is no match, is always linearly
Packit Service ff689b
  dependent on the length of the text being searched.
Packit Service ff689b
Packit Service ff689b
  This algorithm cannot handle TNFAs with back referencing nodes.
Packit Service ff689b
  See `tre-match-backtrack.c'.
Packit Service ff689b
*/
Packit Service ff689b
Packit Service ff689b
typedef struct {
Packit Service ff689b
  tre_tnfa_transition_t *state;
Packit Service ff689b
  regoff_t *tags;
Packit Service ff689b
} tre_tnfa_reach_t;
Packit Service ff689b
Packit Service ff689b
typedef struct {
Packit Service ff689b
  regoff_t pos;
Packit Service ff689b
  regoff_t **tags;
Packit Service ff689b
} tre_reach_pos_t;
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
static reg_errcode_t
Packit Service ff689b
tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string,
Packit Service ff689b
          regoff_t *match_tags, int eflags,
Packit Service ff689b
          regoff_t *match_end_ofs)
Packit Service ff689b
{
Packit Service ff689b
  /* State variables required by GET_NEXT_WCHAR. */
Packit Service ff689b
  tre_char_t prev_c = 0, next_c = 0;
Packit Service ff689b
  const char *str_byte = string;
Packit Service ff689b
  regoff_t pos = -1;
Packit Service ff689b
  regoff_t pos_add_next = 1;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  mbstate_t mbstate;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
  int reg_notbol = eflags & REG_NOTBOL;
Packit Service ff689b
  int reg_noteol = eflags & REG_NOTEOL;
Packit Service ff689b
  int reg_newline = tnfa->cflags & REG_NEWLINE;
Packit Service ff689b
  reg_errcode_t ret;
Packit Service ff689b
Packit Service ff689b
  char *buf;
Packit Service ff689b
  tre_tnfa_transition_t *trans_i;
Packit Service ff689b
  tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i;
Packit Service ff689b
  tre_reach_pos_t *reach_pos;
Packit Service ff689b
  int *tag_i;
Packit Service ff689b
  int num_tags, i;
Packit Service ff689b
Packit Service ff689b
  regoff_t match_eo = -1;    /* end offset of match (-1 if no match found yet) */
Packit Service ff689b
  int new_match = 0;
Packit Service ff689b
  regoff_t *tmp_tags = NULL;
Packit Service ff689b
  regoff_t *tmp_iptr;
Packit Service ff689b
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  memset(&mbstate, '\0', sizeof(mbstate));
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
Packit Service ff689b
  if (!match_tags)
Packit Service ff689b
    num_tags = 0;
Packit Service ff689b
  else
Packit Service ff689b
    num_tags = tnfa->num_tags;
Packit Service ff689b
Packit Service ff689b
  /* Allocate memory for temporary data required for matching.  This needs to
Packit Service ff689b
     be done for every matching operation to be thread safe.  This allocates
Packit Service ff689b
     everything in a single large block with calloc(). */
Packit Service ff689b
  {
Packit Service ff689b
    size_t tbytes, rbytes, pbytes, xbytes, total_bytes;
Packit Service ff689b
    char *tmp_buf;
Packit Service ff689b
Packit Service ff689b
    /* Ensure that tbytes and xbytes*num_states cannot overflow, and that
Packit Service ff689b
     * they don't contribute more than 1/8 of SIZE_MAX to total_bytes. */
Packit Service ff689b
    if (num_tags > SIZE_MAX/(8 * sizeof(regoff_t) * tnfa->num_states))
Packit Service ff689b
      return REG_ESPACE;
Packit Service ff689b
Packit Service ff689b
    /* Likewise check rbytes. */
Packit Service ff689b
    if (tnfa->num_states+1 > SIZE_MAX/(8 * sizeof(*reach_next)))
Packit Service ff689b
      return REG_ESPACE;
Packit Service ff689b
Packit Service ff689b
    /* Likewise check pbytes. */
Packit Service ff689b
    if (tnfa->num_states > SIZE_MAX/(8 * sizeof(*reach_pos)))
Packit Service ff689b
      return REG_ESPACE;
Packit Service ff689b
Packit Service ff689b
    /* Compute the length of the block we need. */
Packit Service ff689b
    tbytes = sizeof(*tmp_tags) * num_tags;
Packit Service ff689b
    rbytes = sizeof(*reach_next) * (tnfa->num_states + 1);
Packit Service ff689b
    pbytes = sizeof(*reach_pos) * tnfa->num_states;
Packit Service ff689b
    xbytes = sizeof(regoff_t) * num_tags;
Packit Service ff689b
    total_bytes =
Packit Service ff689b
      (sizeof(long) - 1) * 4 /* for alignment paddings */
Packit Service ff689b
      + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes;
Packit Service ff689b
Packit Service ff689b
    /* Allocate the memory. */
Packit Service ff689b
    buf = calloc(total_bytes, 1);
Packit Service ff689b
    if (buf == NULL)
Packit Service ff689b
      return REG_ESPACE;
Packit Service ff689b
Packit Service ff689b
    /* Get the various pointers within tmp_buf (properly aligned). */
Packit Service ff689b
    tmp_tags = (void *)buf;
Packit Service ff689b
    tmp_buf = buf + tbytes;
Packit Service ff689b
    tmp_buf += ALIGN(tmp_buf, long);
Packit Service ff689b
    reach_next = (void *)tmp_buf;
Packit Service ff689b
    tmp_buf += rbytes;
Packit Service ff689b
    tmp_buf += ALIGN(tmp_buf, long);
Packit Service ff689b
    reach = (void *)tmp_buf;
Packit Service ff689b
    tmp_buf += rbytes;
Packit Service ff689b
    tmp_buf += ALIGN(tmp_buf, long);
Packit Service ff689b
    reach_pos = (void *)tmp_buf;
Packit Service ff689b
    tmp_buf += pbytes;
Packit Service ff689b
    tmp_buf += ALIGN(tmp_buf, long);
Packit Service ff689b
    for (i = 0; i < tnfa->num_states; i++)
Packit Service ff689b
      {
Packit Service ff689b
  reach[i].tags = (void *)tmp_buf;
Packit Service ff689b
  tmp_buf += xbytes;
Packit Service ff689b
  reach_next[i].tags = (void *)tmp_buf;
Packit Service ff689b
  tmp_buf += xbytes;
Packit Service ff689b
      }
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
  for (i = 0; i < tnfa->num_states; i++)
Packit Service ff689b
    reach_pos[i].pos = -1;
Packit Service ff689b
Packit Service ff689b
  GET_NEXT_WCHAR();
Packit Service ff689b
  pos = 0;
Packit Service ff689b
Packit Service ff689b
  reach_next_i = reach_next;
Packit Service ff689b
  while (1)
Packit Service ff689b
    {
Packit Service ff689b
      /* If no match found yet, add the initial states to `reach_next'. */
Packit Service ff689b
      if (match_eo < 0)
Packit Service ff689b
  {
Packit Service ff689b
    trans_i = tnfa->initial;
Packit Service ff689b
    while (trans_i->state != NULL)
Packit Service ff689b
      {
Packit Service ff689b
        if (reach_pos[trans_i->state_id].pos < pos)
Packit Service ff689b
    {
Packit Service ff689b
      if (trans_i->assertions
Packit Service ff689b
          && CHECK_ASSERTIONS(trans_i->assertions))
Packit Service ff689b
        {
Packit Service ff689b
          trans_i++;
Packit Service ff689b
          continue;
Packit Service ff689b
        }
Packit Service ff689b
Packit Service ff689b
      reach_next_i->state = trans_i->state;
Packit Service ff689b
      for (i = 0; i < num_tags; i++)
Packit Service ff689b
        reach_next_i->tags[i] = -1;
Packit Service ff689b
      tag_i = trans_i->tags;
Packit Service ff689b
      if (tag_i)
Packit Service ff689b
        while (*tag_i >= 0)
Packit Service ff689b
          {
Packit Service ff689b
      if (*tag_i < num_tags)
Packit Service ff689b
        reach_next_i->tags[*tag_i] = pos;
Packit Service ff689b
      tag_i++;
Packit Service ff689b
          }
Packit Service ff689b
      if (reach_next_i->state == tnfa->final)
Packit Service ff689b
        {
Packit Service ff689b
          match_eo = pos;
Packit Service ff689b
          new_match = 1;
Packit Service ff689b
          for (i = 0; i < num_tags; i++)
Packit Service ff689b
      match_tags[i] = reach_next_i->tags[i];
Packit Service ff689b
        }
Packit Service ff689b
      reach_pos[trans_i->state_id].pos = pos;
Packit Service ff689b
      reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
Packit Service ff689b
      reach_next_i++;
Packit Service ff689b
    }
Packit Service ff689b
        trans_i++;
Packit Service ff689b
      }
Packit Service ff689b
    reach_next_i->state = NULL;
Packit Service ff689b
  }
Packit Service ff689b
      else
Packit Service ff689b
  {
Packit Service ff689b
    if (num_tags == 0 || reach_next_i == reach_next)
Packit Service ff689b
      /* We have found a match. */
Packit Service ff689b
      break;
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
      /* Check for end of string. */
Packit Service ff689b
      if (!next_c) break;
Packit Service ff689b
Packit Service ff689b
      GET_NEXT_WCHAR();
Packit Service ff689b
Packit Service ff689b
      /* Swap `reach' and `reach_next'. */
Packit Service ff689b
      reach_i = reach;
Packit Service ff689b
      reach = reach_next;
Packit Service ff689b
      reach_next = reach_i;
Packit Service ff689b
Packit Service ff689b
      /* For each state in `reach', weed out states that don't fulfill the
Packit Service ff689b
   minimal matching conditions. */
Packit Service ff689b
      if (tnfa->num_minimals && new_match)
Packit Service ff689b
  {
Packit Service ff689b
    new_match = 0;
Packit Service ff689b
    reach_next_i = reach_next;
Packit Service ff689b
    for (reach_i = reach; reach_i->state; reach_i++)
Packit Service ff689b
      {
Packit Service ff689b
        int skip = 0;
Packit Service ff689b
        for (i = 0; tnfa->minimal_tags[i] >= 0; i += 2)
Packit Service ff689b
    {
Packit Service ff689b
      int end = tnfa->minimal_tags[i];
Packit Service ff689b
      int start = tnfa->minimal_tags[i + 1];
Packit Service ff689b
      if (end >= num_tags)
Packit Service ff689b
        {
Packit Service ff689b
          skip = 1;
Packit Service ff689b
          break;
Packit Service ff689b
        }
Packit Service ff689b
      else if (reach_i->tags[start] == match_tags[start]
Packit Service ff689b
         && reach_i->tags[end] < match_tags[end])
Packit Service ff689b
        {
Packit Service ff689b
          skip = 1;
Packit Service ff689b
          break;
Packit Service ff689b
        }
Packit Service ff689b
    }
Packit Service ff689b
        if (!skip)
Packit Service ff689b
    {
Packit Service ff689b
      reach_next_i->state = reach_i->state;
Packit Service ff689b
      tmp_iptr = reach_next_i->tags;
Packit Service ff689b
      reach_next_i->tags = reach_i->tags;
Packit Service ff689b
      reach_i->tags = tmp_iptr;
Packit Service ff689b
      reach_next_i++;
Packit Service ff689b
    }
Packit Service ff689b
      }
Packit Service ff689b
    reach_next_i->state = NULL;
Packit Service ff689b
Packit Service ff689b
    /* Swap `reach' and `reach_next'. */
Packit Service ff689b
    reach_i = reach;
Packit Service ff689b
    reach = reach_next;
Packit Service ff689b
    reach_next = reach_i;
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
      /* For each state in `reach' see if there is a transition leaving with
Packit Service ff689b
   the current input symbol to a state not yet in `reach_next', and
Packit Service ff689b
   add the destination states to `reach_next'. */
Packit Service ff689b
      reach_next_i = reach_next;
Packit Service ff689b
      for (reach_i = reach; reach_i->state; reach_i++)
Packit Service ff689b
  {
Packit Service ff689b
    for (trans_i = reach_i->state; trans_i->state; trans_i++)
Packit Service ff689b
      {
Packit Service ff689b
        /* Does this transition match the input symbol? */
Packit Service ff689b
        if (trans_i->code_min <= (tre_cint_t)prev_c &&
Packit Service ff689b
      trans_i->code_max >= (tre_cint_t)prev_c)
Packit Service ff689b
    {
Packit Service ff689b
      if (trans_i->assertions
Packit Service ff689b
          && (CHECK_ASSERTIONS(trans_i->assertions)
Packit Service ff689b
        || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
Packit Service ff689b
        {
Packit Service ff689b
          continue;
Packit Service ff689b
        }
Packit Service ff689b
Packit Service ff689b
      /* Compute the tags after this transition. */
Packit Service ff689b
      for (i = 0; i < num_tags; i++)
Packit Service ff689b
        tmp_tags[i] = reach_i->tags[i];
Packit Service ff689b
      tag_i = trans_i->tags;
Packit Service ff689b
      if (tag_i != NULL)
Packit Service ff689b
        while (*tag_i >= 0)
Packit Service ff689b
          {
Packit Service ff689b
      if (*tag_i < num_tags)
Packit Service ff689b
        tmp_tags[*tag_i] = pos;
Packit Service ff689b
      tag_i++;
Packit Service ff689b
          }
Packit Service ff689b
Packit Service ff689b
      if (reach_pos[trans_i->state_id].pos < pos)
Packit Service ff689b
        {
Packit Service ff689b
          /* Found an unvisited node. */
Packit Service ff689b
          reach_next_i->state = trans_i->state;
Packit Service ff689b
          tmp_iptr = reach_next_i->tags;
Packit Service ff689b
          reach_next_i->tags = tmp_tags;
Packit Service ff689b
          tmp_tags = tmp_iptr;
Packit Service ff689b
          reach_pos[trans_i->state_id].pos = pos;
Packit Service ff689b
          reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
Packit Service ff689b
Packit Service ff689b
          if (reach_next_i->state == tnfa->final
Packit Service ff689b
        && (match_eo == -1
Packit Service ff689b
            || (num_tags > 0
Packit Service ff689b
          && reach_next_i->tags[0] <= match_tags[0])))
Packit Service ff689b
      {
Packit Service ff689b
        match_eo = pos;
Packit Service ff689b
        new_match = 1;
Packit Service ff689b
        for (i = 0; i < num_tags; i++)
Packit Service ff689b
          match_tags[i] = reach_next_i->tags[i];
Packit Service ff689b
      }
Packit Service ff689b
          reach_next_i++;
Packit Service ff689b
Packit Service ff689b
        }
Packit Service ff689b
      else
Packit Service ff689b
        {
Packit Service ff689b
          assert(reach_pos[trans_i->state_id].pos == pos);
Packit Service ff689b
          /* Another path has also reached this state.  We choose
Packit Service ff689b
       the winner by examining the tag values for both
Packit Service ff689b
       paths. */
Packit Service ff689b
          if (tre_tag_order(num_tags, tnfa->tag_directions,
Packit Service ff689b
          tmp_tags,
Packit Service ff689b
          *reach_pos[trans_i->state_id].tags))
Packit Service ff689b
      {
Packit Service ff689b
        /* The new path wins. */
Packit Service ff689b
        tmp_iptr = *reach_pos[trans_i->state_id].tags;
Packit Service ff689b
        *reach_pos[trans_i->state_id].tags = tmp_tags;
Packit Service ff689b
        if (trans_i->state == tnfa->final)
Packit Service ff689b
          {
Packit Service ff689b
            match_eo = pos;
Packit Service ff689b
            new_match = 1;
Packit Service ff689b
            for (i = 0; i < num_tags; i++)
Packit Service ff689b
        match_tags[i] = tmp_tags[i];
Packit Service ff689b
          }
Packit Service ff689b
        tmp_tags = tmp_iptr;
Packit Service ff689b
      }
Packit Service ff689b
        }
Packit Service ff689b
    }
Packit Service ff689b
      }
Packit Service ff689b
  }
Packit Service ff689b
      reach_next_i->state = NULL;
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  *match_end_ofs = match_eo;
Packit Service ff689b
  ret = match_eo >= 0 ? REG_OK : REG_NOMATCH;
Packit Service ff689b
error_exit:
Packit Service ff689b
  xfree(buf);
Packit Service ff689b
  return ret;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
/***********************************************************************
Packit Service ff689b
 from tre-match-backtrack.c
Packit Service ff689b
***********************************************************************/
Packit Service ff689b
Packit Service ff689b
/*
Packit Service ff689b
  This matcher is for regexps that use back referencing.  Regexp matching
Packit Service ff689b
  with back referencing is an NP-complete problem on the number of back
Packit Service ff689b
  references.  The easiest way to match them is to use a backtracking
Packit Service ff689b
  routine which basically goes through all possible paths in the TNFA
Packit Service ff689b
  and chooses the one which results in the best (leftmost and longest)
Packit Service ff689b
  match.  This can be spectacularly expensive and may run out of stack
Packit Service ff689b
  space, but there really is no better known generic algorithm.  Quoting
Packit Service ff689b
  Henry Spencer from comp.compilers:
Packit Service ff689b
  <URL: http://compilers.iecc.com/comparch/article/93-03-102>
Packit Service ff689b
Packit Service ff689b
    POSIX.2 REs require longest match, which is really exciting to
Packit Service ff689b
    implement since the obsolete ("basic") variant also includes
Packit Service ff689b
    \<digit>.  I haven't found a better way of tackling this than doing
Packit Service ff689b
    a preliminary match using a DFA (or simulation) on a modified RE
Packit Service ff689b
    that just replicates subREs for \<digit>, and then doing a
Packit Service ff689b
    backtracking match to determine whether the subRE matches were
Packit Service ff689b
    right.  This can be rather slow, but I console myself with the
Packit Service ff689b
    thought that people who use \<digit> deserve very slow execution.
Packit Service ff689b
    (Pun unintentional but very appropriate.)
Packit Service ff689b
Packit Service ff689b
*/
Packit Service ff689b
Packit Service ff689b
typedef struct {
Packit Service ff689b
  regoff_t pos;
Packit Service ff689b
  const char *str_byte;
Packit Service ff689b
  tre_tnfa_transition_t *state;
Packit Service ff689b
  int state_id;
Packit Service ff689b
  int next_c;
Packit Service ff689b
  regoff_t *tags;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  mbstate_t mbstate;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
} tre_backtrack_item_t;
Packit Service ff689b
Packit Service ff689b
typedef struct tre_backtrack_struct {
Packit Service ff689b
  tre_backtrack_item_t item;
Packit Service ff689b
  struct tre_backtrack_struct *prev;
Packit Service ff689b
  struct tre_backtrack_struct *next;
Packit Service ff689b
} *tre_backtrack_t;
Packit Service ff689b
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
#define BT_STACK_MBSTATE_IN  stack->item.mbstate = (mbstate)
Packit Service ff689b
#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate
Packit Service ff689b
#else /* !TRE_MBSTATE */
Packit Service ff689b
#define BT_STACK_MBSTATE_IN
Packit Service ff689b
#define BT_STACK_MBSTATE_OUT
Packit Service ff689b
#endif /* !TRE_MBSTATE */
Packit Service ff689b
Packit Service ff689b
#define tre_bt_mem_new      tre_mem_new
Packit Service ff689b
#define tre_bt_mem_alloc    tre_mem_alloc
Packit Service ff689b
#define tre_bt_mem_destroy    tre_mem_destroy
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \
Packit Service ff689b
  do                        \
Packit Service ff689b
    {                       \
Packit Service ff689b
      int i;                      \
Packit Service ff689b
      if (!stack->next)                   \
Packit Service ff689b
  {                     \
Packit Service ff689b
    tre_backtrack_t s;                  \
Packit Service ff689b
    s = tre_bt_mem_alloc(mem, sizeof(*s));            \
Packit Service ff689b
    if (!s)                   \
Packit Service ff689b
      {                     \
Packit Service ff689b
        tre_bt_mem_destroy(mem);                \
Packit Service ff689b
        if (tags)                   \
Packit Service ff689b
    xfree(tags);                  \
Packit Service ff689b
        if (pmatch)                 \
Packit Service ff689b
    xfree(pmatch);                  \
Packit Service ff689b
        if (states_seen)                  \
Packit Service ff689b
    xfree(states_seen);               \
Packit Service ff689b
        return REG_ESPACE;                \
Packit Service ff689b
      }                     \
Packit Service ff689b
    s->prev = stack;                  \
Packit Service ff689b
    s->next = NULL;                 \
Packit Service ff689b
    s->item.tags = tre_bt_mem_alloc(mem,              \
Packit Service ff689b
            sizeof(*tags) * tnfa->num_tags);    \
Packit Service ff689b
    if (!s->item.tags)                  \
Packit Service ff689b
      {                     \
Packit Service ff689b
        tre_bt_mem_destroy(mem);                \
Packit Service ff689b
        if (tags)                   \
Packit Service ff689b
    xfree(tags);                  \
Packit Service ff689b
        if (pmatch)                 \
Packit Service ff689b
    xfree(pmatch);                  \
Packit Service ff689b
        if (states_seen)                  \
Packit Service ff689b
    xfree(states_seen);               \
Packit Service ff689b
        return REG_ESPACE;                \
Packit Service ff689b
      }                     \
Packit Service ff689b
    stack->next = s;                  \
Packit Service ff689b
    stack = s;                    \
Packit Service ff689b
  }                     \
Packit Service ff689b
      else                      \
Packit Service ff689b
  stack = stack->next;                  \
Packit Service ff689b
      stack->item.pos = (_pos);                 \
Packit Service ff689b
      stack->item.str_byte = (_str_byte);             \
Packit Service ff689b
      stack->item.state = (_state);               \
Packit Service ff689b
      stack->item.state_id = (_state_id);             \
Packit Service ff689b
      stack->item.next_c = (_next_c);               \
Packit Service ff689b
      for (i = 0; i < tnfa->num_tags; i++)              \
Packit Service ff689b
  stack->item.tags[i] = (_tags)[i];             \
Packit Service ff689b
      BT_STACK_MBSTATE_IN;                  \
Packit Service ff689b
    }                       \
Packit Service ff689b
  while (0)
Packit Service ff689b
Packit Service ff689b
#define BT_STACK_POP()                    \
Packit Service ff689b
  do                        \
Packit Service ff689b
    {                       \
Packit Service ff689b
      int i;                      \
Packit Service ff689b
      assert(stack->prev);                  \
Packit Service ff689b
      pos = stack->item.pos;                  \
Packit Service ff689b
      str_byte = stack->item.str_byte;                \
Packit Service ff689b
      state = stack->item.state;                \
Packit Service ff689b
      next_c = stack->item.next_c;                \
Packit Service ff689b
      for (i = 0; i < tnfa->num_tags; i++)              \
Packit Service ff689b
  tags[i] = stack->item.tags[i];                \
Packit Service ff689b
      BT_STACK_MBSTATE_OUT;                 \
Packit Service ff689b
      stack = stack->prev;                  \
Packit Service ff689b
    }                       \
Packit Service ff689b
  while (0)
Packit Service ff689b
Packit Service ff689b
#undef MIN
Packit Service ff689b
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
Packit Service ff689b
Packit Service ff689b
static reg_errcode_t
Packit Service ff689b
tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string,
Packit Service ff689b
           regoff_t *match_tags, int eflags, regoff_t *match_end_ofs)
Packit Service ff689b
{
Packit Service ff689b
  /* State variables required by GET_NEXT_WCHAR. */
Packit Service ff689b
  tre_char_t prev_c = 0, next_c = 0;
Packit Service ff689b
  const char *str_byte = string;
Packit Service ff689b
  regoff_t pos = 0;
Packit Service ff689b
  regoff_t pos_add_next = 1;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  mbstate_t mbstate;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
  int reg_notbol = eflags & REG_NOTBOL;
Packit Service ff689b
  int reg_noteol = eflags & REG_NOTEOL;
Packit Service ff689b
  int reg_newline = tnfa->cflags & REG_NEWLINE;
Packit Service ff689b
Packit Service ff689b
  /* These are used to remember the necessary values of the above
Packit Service ff689b
     variables to return to the position where the current search
Packit Service ff689b
     started from. */
Packit Service ff689b
  int next_c_start;
Packit Service ff689b
  const char *str_byte_start;
Packit Service ff689b
  regoff_t pos_start = -1;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  mbstate_t mbstate_start;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
Packit Service ff689b
  /* End offset of best match so far, or -1 if no match found yet. */
Packit Service ff689b
  regoff_t match_eo = -1;
Packit Service ff689b
  /* Tag arrays. */
Packit Service ff689b
  int *next_tags;
Packit Service ff689b
  regoff_t *tags = NULL;
Packit Service ff689b
  /* Current TNFA state. */
Packit Service ff689b
  tre_tnfa_transition_t *state;
Packit Service ff689b
  int *states_seen = NULL;
Packit Service ff689b
Packit Service ff689b
  /* Memory allocator to for allocating the backtracking stack. */
Packit Service ff689b
  tre_mem_t mem = tre_bt_mem_new();
Packit Service ff689b
Packit Service ff689b
  /* The backtracking stack. */
Packit Service ff689b
  tre_backtrack_t stack;
Packit Service ff689b
Packit Service ff689b
  tre_tnfa_transition_t *trans_i;
Packit Service ff689b
  regmatch_t *pmatch = NULL;
Packit Service ff689b
  int ret;
Packit Service ff689b
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  memset(&mbstate, '\0', sizeof(mbstate));
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
Packit Service ff689b
  if (!mem)
Packit Service ff689b
    return REG_ESPACE;
Packit Service ff689b
  stack = tre_bt_mem_alloc(mem, sizeof(*stack));
Packit Service ff689b
  if (!stack)
Packit Service ff689b
    {
Packit Service ff689b
      ret = REG_ESPACE;
Packit Service ff689b
      goto error_exit;
Packit Service ff689b
    }
Packit Service ff689b
  stack->prev = NULL;
Packit Service ff689b
  stack->next = NULL;
Packit Service ff689b
Packit Service ff689b
  if (tnfa->num_tags)
Packit Service ff689b
    {
Packit Service ff689b
      tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
Packit Service ff689b
      if (!tags)
Packit Service ff689b
  {
Packit Service ff689b
    ret = REG_ESPACE;
Packit Service ff689b
    goto error_exit;
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
  if (tnfa->num_submatches)
Packit Service ff689b
    {
Packit Service ff689b
      pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches);
Packit Service ff689b
      if (!pmatch)
Packit Service ff689b
  {
Packit Service ff689b
    ret = REG_ESPACE;
Packit Service ff689b
    goto error_exit;
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
  if (tnfa->num_states)
Packit Service ff689b
    {
Packit Service ff689b
      states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states);
Packit Service ff689b
      if (!states_seen)
Packit Service ff689b
  {
Packit Service ff689b
    ret = REG_ESPACE;
Packit Service ff689b
    goto error_exit;
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
 retry:
Packit Service ff689b
  {
Packit Service ff689b
    int i;
Packit Service ff689b
    for (i = 0; i < tnfa->num_tags; i++)
Packit Service ff689b
      {
Packit Service ff689b
  tags[i] = -1;
Packit Service ff689b
  if (match_tags)
Packit Service ff689b
    match_tags[i] = -1;
Packit Service ff689b
      }
Packit Service ff689b
    for (i = 0; i < tnfa->num_states; i++)
Packit Service ff689b
      states_seen[i] = 0;
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
  state = NULL;
Packit Service ff689b
  pos = pos_start;
Packit Service ff689b
  GET_NEXT_WCHAR();
Packit Service ff689b
  pos_start = pos;
Packit Service ff689b
  next_c_start = next_c;
Packit Service ff689b
  str_byte_start = str_byte;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
  mbstate_start = mbstate;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
Packit Service ff689b
  /* Handle initial states. */
Packit Service ff689b
  next_tags = NULL;
Packit Service ff689b
  for (trans_i = tnfa->initial; trans_i->state; trans_i++)
Packit Service ff689b
    {
Packit Service ff689b
      if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions))
Packit Service ff689b
  {
Packit Service ff689b
    continue;
Packit Service ff689b
  }
Packit Service ff689b
      if (state == NULL)
Packit Service ff689b
  {
Packit Service ff689b
    /* Start from this state. */
Packit Service ff689b
    state = trans_i->state;
Packit Service ff689b
    next_tags = trans_i->tags;
Packit Service ff689b
  }
Packit Service ff689b
      else
Packit Service ff689b
  {
Packit Service ff689b
    /* Backtrack to this state. */
Packit Service ff689b
    BT_STACK_PUSH(pos, str_byte, 0, trans_i->state,
Packit Service ff689b
      trans_i->state_id, next_c, tags, mbstate);
Packit Service ff689b
    {
Packit Service ff689b
      int *tmp = trans_i->tags;
Packit Service ff689b
      if (tmp)
Packit Service ff689b
        while (*tmp >= 0)
Packit Service ff689b
    stack->item.tags[*tmp++] = pos;
Packit Service ff689b
    }
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  if (next_tags)
Packit Service ff689b
    for (; *next_tags >= 0; next_tags++)
Packit Service ff689b
      tags[*next_tags] = pos;
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
  if (state == NULL)
Packit Service ff689b
    goto backtrack;
Packit Service ff689b
Packit Service ff689b
  while (1)
Packit Service ff689b
    {
Packit Service ff689b
      tre_tnfa_transition_t *next_state;
Packit Service ff689b
      int empty_br_match;
Packit Service ff689b
Packit Service ff689b
      if (state == tnfa->final)
Packit Service ff689b
  {
Packit Service ff689b
    if (match_eo < pos
Packit Service ff689b
        || (match_eo == pos
Packit Service ff689b
      && match_tags
Packit Service ff689b
      && tre_tag_order(tnfa->num_tags, tnfa->tag_directions,
Packit Service ff689b
           tags, match_tags)))
Packit Service ff689b
      {
Packit Service ff689b
        int i;
Packit Service ff689b
        /* This match wins the previous match. */
Packit Service ff689b
        match_eo = pos;
Packit Service ff689b
        if (match_tags)
Packit Service ff689b
    for (i = 0; i < tnfa->num_tags; i++)
Packit Service ff689b
      match_tags[i] = tags[i];
Packit Service ff689b
      }
Packit Service ff689b
    /* Our TNFAs never have transitions leaving from the final state,
Packit Service ff689b
       so we jump right to backtracking. */
Packit Service ff689b
    goto backtrack;
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
      /* Go to the next character in the input string. */
Packit Service ff689b
      empty_br_match = 0;
Packit Service ff689b
      trans_i = state;
Packit Service ff689b
      if (trans_i->state && trans_i->assertions & ASSERT_BACKREF)
Packit Service ff689b
  {
Packit Service ff689b
    /* This is a back reference state.  All transitions leaving from
Packit Service ff689b
       this state have the same back reference "assertion".  Instead
Packit Service ff689b
       of reading the next character, we match the back reference. */
Packit Service ff689b
    regoff_t so, eo;
Packit Service ff689b
    int bt = trans_i->u.backref;
Packit Service ff689b
    regoff_t bt_len;
Packit Service ff689b
    int result;
Packit Service ff689b
Packit Service ff689b
    /* Get the substring we need to match against.  Remember to
Packit Service ff689b
       turn off REG_NOSUB temporarily. */
Packit Service ff689b
    tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & ~REG_NOSUB,
Packit Service ff689b
        tnfa, tags, pos);
Packit Service ff689b
    so = pmatch[bt].rm_so;
Packit Service ff689b
    eo = pmatch[bt].rm_eo;
Packit Service ff689b
    bt_len = eo - so;
Packit Service ff689b
Packit Service ff689b
    result = strncmp((const char*)string + so, str_byte - 1,
Packit Service ff689b
         (size_t)bt_len);
Packit Service ff689b
Packit Service ff689b
    if (result == 0)
Packit Service ff689b
      {
Packit Service ff689b
        /* Back reference matched.  Check for infinite loop. */
Packit Service ff689b
        if (bt_len == 0)
Packit Service ff689b
    empty_br_match = 1;
Packit Service ff689b
        if (empty_br_match && states_seen[trans_i->state_id])
Packit Service ff689b
    {
Packit Service ff689b
      goto backtrack;
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
        states_seen[trans_i->state_id] = empty_br_match;
Packit Service ff689b
Packit Service ff689b
        /* Advance in input string and resync `prev_c', `next_c'
Packit Service ff689b
     and pos. */
Packit Service ff689b
        str_byte += bt_len - 1;
Packit Service ff689b
        pos += bt_len - 1;
Packit Service ff689b
        GET_NEXT_WCHAR();
Packit Service ff689b
      }
Packit Service ff689b
    else
Packit Service ff689b
      {
Packit Service ff689b
        goto backtrack;
Packit Service ff689b
      }
Packit Service ff689b
  }
Packit Service ff689b
      else
Packit Service ff689b
  {
Packit Service ff689b
    /* Check for end of string. */
Packit Service ff689b
    if (next_c == L'\0')
Packit Service ff689b
    goto backtrack;
Packit Service ff689b
Packit Service ff689b
    /* Read the next character. */
Packit Service ff689b
    GET_NEXT_WCHAR();
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
      next_state = NULL;
Packit Service ff689b
      for (trans_i = state; trans_i->state; trans_i++)
Packit Service ff689b
  {
Packit Service ff689b
    if (trans_i->code_min <= (tre_cint_t)prev_c
Packit Service ff689b
        && trans_i->code_max >= (tre_cint_t)prev_c)
Packit Service ff689b
      {
Packit Service ff689b
        if (trans_i->assertions
Packit Service ff689b
      && (CHECK_ASSERTIONS(trans_i->assertions)
Packit Service ff689b
          || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
Packit Service ff689b
    {
Packit Service ff689b
      continue;
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
        if (next_state == NULL)
Packit Service ff689b
    {
Packit Service ff689b
      /* First matching transition. */
Packit Service ff689b
      next_state = trans_i->state;
Packit Service ff689b
      next_tags = trans_i->tags;
Packit Service ff689b
    }
Packit Service ff689b
        else
Packit Service ff689b
    {
Packit Service ff689b
      /* Second matching transition.  We may need to backtrack here
Packit Service ff689b
         to take this transition instead of the first one, so we
Packit Service ff689b
         push this transition in the backtracking stack so we can
Packit Service ff689b
         jump back here if needed. */
Packit Service ff689b
      BT_STACK_PUSH(pos, str_byte, 0, trans_i->state,
Packit Service ff689b
        trans_i->state_id, next_c, tags, mbstate);
Packit Service ff689b
      {
Packit Service ff689b
        int *tmp;
Packit Service ff689b
        for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++)
Packit Service ff689b
          stack->item.tags[*tmp] = pos;
Packit Service ff689b
      }
Packit Service ff689b
#if 0 /* XXX - it's important not to look at all transitions here to keep
Packit Service ff689b
   the stack small! */
Packit Service ff689b
      break;
Packit Service ff689b
#endif
Packit Service ff689b
    }
Packit Service ff689b
      }
Packit Service ff689b
  }
Packit Service ff689b
Packit Service ff689b
      if (next_state != NULL)
Packit Service ff689b
  {
Packit Service ff689b
    /* Matching transitions were found.  Take the first one. */
Packit Service ff689b
    state = next_state;
Packit Service ff689b
Packit Service ff689b
    /* Update the tag values. */
Packit Service ff689b
    if (next_tags)
Packit Service ff689b
      while (*next_tags >= 0)
Packit Service ff689b
        tags[*next_tags++] = pos;
Packit Service ff689b
  }
Packit Service ff689b
      else
Packit Service ff689b
  {
Packit Service ff689b
  backtrack:
Packit Service ff689b
    /* A matching transition was not found.  Try to backtrack. */
Packit Service ff689b
    if (stack->prev)
Packit Service ff689b
      {
Packit Service ff689b
        if (stack->item.state->assertions & ASSERT_BACKREF)
Packit Service ff689b
    {
Packit Service ff689b
      states_seen[stack->item.state_id] = 0;
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
        BT_STACK_POP();
Packit Service ff689b
      }
Packit Service ff689b
    else if (match_eo < 0)
Packit Service ff689b
      {
Packit Service ff689b
        /* Try starting from a later position in the input string. */
Packit Service ff689b
        /* Check for end of string. */
Packit Service ff689b
        if (next_c == L'\0')
Packit Service ff689b
        {
Packit Service ff689b
          break;
Packit Service ff689b
        }
Packit Service ff689b
        next_c = next_c_start;
Packit Service ff689b
#ifdef TRE_MBSTATE
Packit Service ff689b
        mbstate = mbstate_start;
Packit Service ff689b
#endif /* TRE_MBSTATE */
Packit Service ff689b
        str_byte = str_byte_start;
Packit Service ff689b
        goto retry;
Packit Service ff689b
      }
Packit Service ff689b
    else
Packit Service ff689b
      {
Packit Service ff689b
        break;
Packit Service ff689b
      }
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  ret = match_eo >= 0 ? REG_OK : REG_NOMATCH;
Packit Service ff689b
  *match_end_ofs = match_eo;
Packit Service ff689b
Packit Service ff689b
 error_exit:
Packit Service ff689b
  tre_bt_mem_destroy(mem);
Packit Service ff689b
#ifndef TRE_USE_ALLOCA
Packit Service ff689b
  if (tags)
Packit Service ff689b
    xfree(tags);
Packit Service ff689b
  if (pmatch)
Packit Service ff689b
    xfree(pmatch);
Packit Service ff689b
  if (states_seen)
Packit Service ff689b
    xfree(states_seen);
Packit Service ff689b
#endif /* !TRE_USE_ALLOCA */
Packit Service ff689b
Packit Service ff689b
  return ret;
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
/***********************************************************************
Packit Service ff689b
 from regexec.c
Packit Service ff689b
***********************************************************************/
Packit Service ff689b
Packit Service ff689b
/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match
Packit Service ff689b
   endpoint values. */
Packit Service ff689b
static void
Packit Service ff689b
tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
Packit Service ff689b
    const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo)
Packit Service ff689b
{
Packit Service ff689b
  tre_submatch_data_t *submatch_data;
Packit Service ff689b
  unsigned int i, j;
Packit Service ff689b
  int *parents;
Packit Service ff689b
Packit Service ff689b
  i = 0;
Packit Service ff689b
  if (match_eo >= 0 && !(cflags & REG_NOSUB))
Packit Service ff689b
    {
Packit Service ff689b
      /* Construct submatch offsets from the tags. */
Packit Service ff689b
      submatch_data = tnfa->submatch_data;
Packit Service ff689b
      while (i < tnfa->num_submatches && i < nmatch)
Packit Service ff689b
  {
Packit Service ff689b
    if (submatch_data[i].so_tag == tnfa->end_tag)
Packit Service ff689b
      pmatch[i].rm_so = match_eo;
Packit Service ff689b
    else
Packit Service ff689b
      pmatch[i].rm_so = tags[submatch_data[i].so_tag];
Packit Service ff689b
Packit Service ff689b
    if (submatch_data[i].eo_tag == tnfa->end_tag)
Packit Service ff689b
      pmatch[i].rm_eo = match_eo;
Packit Service ff689b
    else
Packit Service ff689b
      pmatch[i].rm_eo = tags[submatch_data[i].eo_tag];
Packit Service ff689b
Packit Service ff689b
    /* If either of the endpoints were not used, this submatch
Packit Service ff689b
       was not part of the match. */
Packit Service ff689b
    if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1)
Packit Service ff689b
      pmatch[i].rm_so = pmatch[i].rm_eo = -1;
Packit Service ff689b
Packit Service ff689b
    i++;
Packit Service ff689b
  }
Packit Service ff689b
      /* Reset all submatches that are not within all of their parent
Packit Service ff689b
   submatches. */
Packit Service ff689b
      i = 0;
Packit Service ff689b
      while (i < tnfa->num_submatches && i < nmatch)
Packit Service ff689b
  {
Packit Service ff689b
    if (pmatch[i].rm_eo == -1)
Packit Service ff689b
      assert(pmatch[i].rm_so == -1);
Packit Service ff689b
    assert(pmatch[i].rm_so <= pmatch[i].rm_eo);
Packit Service ff689b
Packit Service ff689b
    parents = submatch_data[i].parents;
Packit Service ff689b
    if (parents != NULL)
Packit Service ff689b
      for (j = 0; parents[j] >= 0; j++)
Packit Service ff689b
        {
Packit Service ff689b
    if (pmatch[i].rm_so < pmatch[parents[j]].rm_so
Packit Service ff689b
        || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo)
Packit Service ff689b
      pmatch[i].rm_so = pmatch[i].rm_eo = -1;
Packit Service ff689b
        }
Packit Service ff689b
    i++;
Packit Service ff689b
  }
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  while (i < nmatch)
Packit Service ff689b
    {
Packit Service ff689b
      pmatch[i].rm_so = -1;
Packit Service ff689b
      pmatch[i].rm_eo = -1;
Packit Service ff689b
      i++;
Packit Service ff689b
    }
Packit Service ff689b
}
Packit Service ff689b
Packit Service ff689b
Packit Service ff689b
/*
Packit Service ff689b
  Wrapper functions for POSIX compatible regexp matching.
Packit Service ff689b
*/
Packit Service ff689b
Packit Service ff689b
int
Packit Service ff689b
regexec(const regex_t *__restrict preg, const char *__restrict string,
Packit Service ff689b
    size_t nmatch, regmatch_t * __restrict pmatch, int eflags)
Packit Service ff689b
{
Packit Service ff689b
  tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
Packit Service ff689b
  reg_errcode_t status;
Packit Service ff689b
  regoff_t *tags = NULL, eo;
Packit Service ff689b
  if (tnfa->cflags & REG_NOSUB) nmatch = 0;
Packit Service ff689b
  if (tnfa->num_tags > 0 && nmatch > 0)
Packit Service ff689b
    {
Packit Service ff689b
      tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
Packit Service ff689b
      if (tags == NULL)
Packit Service ff689b
  return REG_ESPACE;
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  /* Dispatch to the appropriate matcher. */
Packit Service ff689b
  if (tnfa->have_backrefs)
Packit Service ff689b
    {
Packit Service ff689b
      /* The regex has back references, use the backtracking matcher. */
Packit Service ff689b
      status = tre_tnfa_run_backtrack(tnfa, string, tags, eflags, &eo);
Packit Service ff689b
    }
Packit Service ff689b
  else
Packit Service ff689b
    {
Packit Service ff689b
      /* Exact matching, no back references, use the parallel matcher. */
Packit Service ff689b
      status = tre_tnfa_run_parallel(tnfa, string, tags, eflags, &eo);
Packit Service ff689b
    }
Packit Service ff689b
Packit Service ff689b
  if (status == REG_OK)
Packit Service ff689b
    /* A match was found, so fill the submatch registers. */
Packit Service ff689b
    tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo);
Packit Service ff689b
  if (tags)
Packit Service ff689b
    xfree(tags);
Packit Service ff689b
  return status;
Packit Service ff689b
}