packages feed

EtaMOO-0.2.0.0: src/cbits/match.c

# include <string.h>
# include "match.h"

# define MAX_CAPTURES   10

/*
 * Structure for capturing rmatch results
 */
typedef struct {
  int ovec[MAX_CAPTURES * 2];
  int valid;
} rmatch_data_t;

/*
 * PCRE callout function used to capture rmatch results
 *
 * This function may be called by PCRE each time the (?C) pattern is
 * encountered, which we have arranged to occur at the end of each successful
 * pattern match. To find the rightmost match, we record the match found so
 * far if it is further right and/or longer than the last found match, then
 * tell PCRE to continue matching as if the match had failed.
 */
static
int rmatch_callout(pcre_callout_block *block)
{
  rmatch_data_t *rmatch = block->callout_data;

  if (!rmatch->valid || block->start_match > rmatch->ovec[0] ||
      (block->start_match == rmatch->ovec[0] &&
       block->current_position > rmatch->ovec[1])) {
    /* make a copy of the offsets vector so the last such vector found can be
       returned as the rightmost match */
    rmatch->ovec[0] = block->start_match;
    rmatch->ovec[1] = block->current_position;
    memcpy(&rmatch->ovec[2], &block->offset_vector[2],
           sizeof(rmatch->ovec[2]) * 2 * (block->capture_top - 1));

    rmatch->valid = block->capture_top;
  }

  return 1;  /* cause match failure at current point, but continue trying */
}

/*
 * match() helper function
 *
 * This function exists so that it can be called by the Haskell runtime
 * without any other threads running. This is necessary because it needs to
 * convey callout information to PCRE via global variable.
 */
int match_helper(const pcre *code, pcre_extra *extra,
                 const char *subject, int length,
                 int options, int ovector[MAX_CAPTURES * 3])
{
  extra->flags &= ~PCRE_EXTRA_CALLOUT_DATA;

  pcre_callout = 0;

  return pcre_exec(code, extra, subject, length, 0,
		   options, ovector, MAX_CAPTURES * 3);
}

/*
 * rmatch() helper function
 *
 * This function exists so that it can be called by the Haskell runtime
 * without any other threads running. This is necessary because it needs to
 * convey callout information to PCRE via global variable.
 */
int rmatch_helper(const pcre *code, pcre_extra *extra,
                  const char *subject, int length,
                  int options, int ovector[MAX_CAPTURES * 3])
{
  rmatch_data_t rmatch;
  int rc;

  rmatch.valid = 0;

  extra->callout_data = &rmatch;
  extra->flags |= PCRE_EXTRA_CALLOUT_DATA;

  pcre_callout = rmatch_callout;

  rc = pcre_exec(code, extra, subject, length, 0,
		 options, ovector, MAX_CAPTURES * 3);
  if (rc == PCRE_ERROR_NOMATCH && rmatch.valid) {
    rc = rmatch.valid;
    memcpy(ovector, &rmatch.ovec[0], sizeof(ovector[0]) * 2 * rc);
  }

  return rc;
}