regex.c:3524
static int
re_match_exec(bufp, string_arg, size, pos, beg, regs)
     struct re_pattern_buffer *bufp;
     const char *string_arg;
     int size, pos, beg;
     struct re_registers *regs;
{
  register unsigned char *p = (unsigned char*)bufp->buffer;
  unsigned char *p1;

  /* Pointer to beyond end of buffer.  */
  register unsigned char *pend = p + bufp->used;

  unsigned num_regs = bufp->re_nsub;

  unsigned char *string = (unsigned char*)string_arg;

  register unsigned char *d, *dend;
  register int mcnt;			/* Multipurpose.  */
  int options = bufp->options;

  /* Failure point stack.  Each place that can handle a failure further
     down the line pushes a failure point on this stack.  It consists of
     restart, regend, and reg_info for all registers corresponding to the
     subexpressions we're currently inside, plus the number of such
     registers, and, finally, two char *'s.  The first char * is where to
     resume scanning the pattern; the second one is where to resume
     scanning the strings.  If the latter is zero, the failure point is a
     ``dummy''; if a failure happens and the failure point is a dummy, it
     gets discarded and the next next one is tried.  */

  unsigned char **stacka;
  unsigned char **stackb;
  unsigned char **stackp;
  unsigned char **stacke;

  /* Information on the contents of registers. These are pointers into
     the input strings; they record just what was matched (on this
     attempt) by a subexpression part of the pattern, that is, the
     regnum-th regstart pointer points to where in the pattern we began
     matching and the regnum-th regend points to right after where we
     stopped matching the regnum-th subexpression.  (The zeroth register
     keeps track of what the whole pattern matches.)  */

  unsigned char **regstart = bufp->regstart;
  unsigned char **regend = bufp->regend;

  /* If a group that's operated upon by a repetition operator fails to
     match anything, then the register for its start will need to be
     restored because it will have been set to wherever in the string we
     are when we last see its open-group operator.  Similarly for a
     register's end.  */
  unsigned char **old_regstart = bufp->old_regstart;
  unsigned char **old_regend = bufp->old_regend;

  /* The is_active field of reg_info helps us keep track of which (possibly
     nested) subexpressions we are currently in. The matched_something
     field of reg_info[reg_num] helps us tell whether or not we have
     matched any of the pattern so far this time through the reg_num-th
     subexpression.  These two fields get reset each time through any
     loop their register is in.  */

  register_info_type *reg_info = bufp->reg_info;

  /* The following record the register info as found in the above
     variables when we find a match better than any we've seen before. 
     This happens as we backtrack through the failure points, which in
     turn happens only if we have not yet matched the entire string.  */

  unsigned best_regs_set = 0;
  unsigned char **best_regstart = bufp->best_regstart;
  unsigned char **best_regend = bufp->best_regend;

  int num_failure_counts = 0;

  if (regs) {
    init_regs(regs, num_regs);
  }

  /* Initialize the stack. */
  stacka = RE_TALLOC(MAX_NUM_FAILURE_ITEMS * NFAILURES, unsigned char*);
  stackb = stacka;
  stackp = stackb;
  stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES];

#ifdef DEBUG_REGEX
  fprintf(stderr, "Entering re_match(%s)\n", string_arg);
#endif

  /* Initialize subexpression text positions to -1 to mark ones that no
     ( or ( and ) or ) has been seen for. Also set all registers to
     inactive and mark them as not having matched anything or ever
     failed. */
  for (mcnt = 0; mcnt < num_regs; mcnt++) {
    regstart[mcnt] = regend[mcnt]
      = old_regstart[mcnt] = old_regend[mcnt]
      = best_regstart[mcnt] = best_regend[mcnt] = REG_UNSET_VALUE;
#ifdef __CHECKER__
    reg_info[mcnt].word = 0;
#endif
    IS_ACTIVE (reg_info[mcnt]) = 0;
    MATCHED_SOMETHING (reg_info[mcnt]) = 0;
  }

  /* Set up pointers to ends of strings.
     Don't allow the second string to be empty unless both are empty.  */


  /* `p' scans through the pattern as `d' scans through the data. `dend'
     is the end of the input string that `d' points within. `d' is
     advanced into the following input string whenever necessary, but
     this happens before fetching; therefore, at the beginning of the
     loop, `d' can be pointing at the end of a string, but it cannot
     equal string2.  */

  d = string + pos, dend = string + size;

  /* This loops over pattern commands.  It exits by returning from the
     function if match is complete, or it drops through if match fails
     at this starting point in the input data.  */

  for (;;) {
#ifdef DEBUG_REGEX
    fprintf(stderr,
	    "regex loop(%d):  matching 0x%02d\n",
	    p - (unsigned char*)bufp->buffer,
	    *p);
#endif
    /* End of pattern means we might have succeeded.  */
    if (p == pend) {
      /* If not end of string, try backtracking.  Otherwise done.  */
      if ((bufp->options & RE_OPTION_LONGEST) && d != dend) {
	if (best_regs_set) /* non-greedy, no need to backtrack */
	  goto restore_best_regs;
	while (stackp != stackb && stackp[-1] == NON_GREEDY) {
	  if (best_regs_set) /* non-greedy, no need to backtrack */
	    goto restore_best_regs;
	  POP_FAILURE_POINT();
	}
	if (stackp != stackb) {
	  /* More failure points to try.  */

	  /* If exceeds best match so far, save it.  */
	  if (! best_regs_set || (d > best_regend[0])) {
	    best_regs_set = 1;
	    best_regend[0] = d;	/* Never use regstart[0].  */

	    for (mcnt = 1; mcnt < num_regs; mcnt++) {
	      best_regstart[mcnt] = regstart[mcnt];
	      best_regend[mcnt] = regend[mcnt];
	    }
	  }
	  goto fail;	       
	}
	/* If no failure points, don't restore garbage.  */
	else if (best_regs_set) {
	restore_best_regs:
	  /* Restore best match.  */
	  d = best_regend[0];

	  for (mcnt = 0; mcnt < num_regs; mcnt++) {
	    regstart[mcnt] = best_regstart[mcnt];
	    regend[mcnt] = best_regend[mcnt];
	  }
	}
      }

      /* If caller wants register contents data back, convert it 
	 to indices.  */
      if (regs) {
	regs->beg[0] = pos;
	regs->end[0] = d - string;
	for (mcnt = 1; mcnt < num_regs; mcnt++) {
	  if (REG_UNSET(regend[mcnt])) {
	    regs->beg[mcnt] = -1;
	    regs->end[mcnt] = -1;
	    continue;
	  }
	  regs->beg[mcnt] = regstart[mcnt] - string;
	  regs->end[mcnt] = regend[mcnt] - string;
	}
      }
      FREE_AND_RETURN(stackb, (d - pos - string));
    }

    /* Otherwise match next pattern command.  */
#ifdef SWITCH_ENUM_BUG
    switch ((int)((enum regexpcode)*p++))
#else
    switch ((enum regexpcode)*p++)
#endif
      {
	/* ( [or `(', as appropriate] is represented by start_memory,
	   ) by stop_memory.  Both of those commands are followed by
	   a register number in the next byte.  The text matched
	   within the ( and ) is recorded under that number.  */
      case start_memory:
	old_regstart[*p] = regstart[*p];
	regstart[*p] = d;
	IS_ACTIVE(reg_info[*p]) = 1;
	MATCHED_SOMETHING(reg_info[*p]) = 0;
	p += 2;
	continue;

      case stop_memory:
	old_regend[*p] = regend[*p];
	regend[*p] = d;
	IS_ACTIVE(reg_info[*p]) = 0;
	p += 2;
	continue;

      case start_paren:
      case stop_paren:
	break;

	/* \<digit> has been turned into a `duplicate' command which is
	   followed by the numeric value of <digit> as the register number.  */
      case duplicate:
	{
	  int regno = *p++;   /* Get which register to match against */
	  register unsigned char *d2, *dend2;

	  /* Check if there's corresponding group */
	  if (regno >= num_regs) goto fail;
	  /* Check if corresponding group is still open */
	  if (IS_ACTIVE(reg_info[regno])) goto fail;

	  /* Where in input to try to start matching.  */
	  d2 = regstart[regno];
	  if (REG_UNSET(d2)) goto fail;

	  /* Where to stop matching; if both the place to start and
	     the place to stop matching are in the same string, then
	     set to the place to stop, otherwise, for now have to use
	     the end of the first string.  */

	  dend2 = regend[regno];
	  if (REG_UNSET(dend2)) goto fail;
	  for (;;) {
	    /* At end of register contents => success */
	    if (d2 == dend2) break;

	    /* If necessary, advance to next segment in data.  */
	    PREFETCH;

	    /* How many characters left in this segment to match.  */
	    mcnt = dend - d;

	    /* Want how many consecutive characters we can match in
	       one shot, so, if necessary, adjust the count.  */
	    if (mcnt > dend2 - d2)
	      mcnt = dend2 - d2;

	    /* Compare that many; failure if mismatch, else move
	       past them.  */
	    if ((options & RE_OPTION_IGNORECASE) 
		? memcmp_translate(d, d2, mcnt) 
		: memcmp((char*)d, (char*)d2, mcnt))
	      goto fail;
	    d += mcnt, d2 += mcnt;
	  }
	}
	break;

      case start_nowidth:
	PUSH_FAILURE_POINT(0, d);
	if (stackp - stackb > RE_DUP_MAX) {
	   FREE_AND_RETURN(stackb,(-2));
	}
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	STORE_NUMBER(p+mcnt, stackp - stackb);
	continue;

      case stop_nowidth:
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	stackp = stackb + mcnt;
	d = stackp[-3];
	POP_FAILURE_POINT();
	continue;

      case stop_backtrack:
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	stackp = stackb + mcnt;
	POP_FAILURE_POINT();
	continue;

      case pop_and_fail:
	EXTRACT_NUMBER(mcnt, p+1);
	stackp = stackb + mcnt;
	POP_FAILURE_POINT();
	goto fail;

      case anychar:
	PREFETCH;
	if (ismbchar(*d)) {
	  if (d + mbclen(*d) > dend)
	    goto fail;
	  SET_REGS_MATCHED;
	  d += mbclen(*d);
	  break;
	}
	if (!(options&RE_OPTION_MULTILINE)
	    && (TRANSLATE_P() ? translate[*d] : *d) == '\n')
	  goto fail;
	SET_REGS_MATCHED;
	d++;
	break;

      case anychar_repeat:
	for (;;) {
	  PUSH_FAILURE_POINT(p, d);
	  PREFETCH;
	  if (ismbchar(*d)) {
	    if (d + mbclen(*d) > dend)
	      goto fail;
	    SET_REGS_MATCHED;
	    d += mbclen(*d);
	    continue;
	  }
	  if (!(options&RE_OPTION_MULTILINE) &&
	      (TRANSLATE_P() ? translate[*d] : *d) == '\n')
	    goto fail;
	  SET_REGS_MATCHED;
	  d++;
	}
	break;

      case charset:
      case charset_not:
	{
	  int not;	    /* Nonzero for charset_not.  */
	  int part = 0;	    /* true if matched part of mbc */
	  unsigned char *dsave = d + 1;
	  int cc, c;

	  PREFETCH;
	  c = (unsigned char)*d++;
	  if (ismbchar(c)) {
	    if (d + mbclen(c) - 1 <= dend) {
	      cc = c;
	      MBC2WC(c, d);
	      not = is_in_list_mbc(c, p);
	      if (!not) {
		part = not = is_in_list_sbc(cc, p);
	      }
	    } else {
	      not = is_in_list(c, p);
	    }
	  }
	  else {
	    if (TRANSLATE_P())
	      c = (unsigned char)translate[c];
	    not = is_in_list(c, p);
	  }

	  if (*(p - 1) == (unsigned char)charset_not) {
	    not = !not;
	  }
	  if (!not) goto fail;

	  p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*8;
	  SET_REGS_MATCHED;

	  if (part) d = dsave;
	  break;
	}

      case begline:
	if (size == 0 || AT_STRINGS_BEG(d))
	  break;
	if (d[-1] == '\n' && !AT_STRINGS_END(d))
	  break;
	goto fail;

      case endline:
	if (AT_STRINGS_END(d)) {
	  break;
	}
	else if (*d == '\n')
	  break;
	goto fail;

	/* Match at the very beginning of the string. */
      case begbuf:
	if (AT_STRINGS_BEG(d))
	  break;
	goto fail;

	/* Match at the very end of the data. */
      case endbuf:
	if (AT_STRINGS_END(d))
	  break;
	goto fail;

	/* Match at the very end of the data. */
      case endbuf2:
	if (AT_STRINGS_END(d)) {
	  break;
	}
	/* .. or newline just before the end of the data. */
	if (*d == '\n' && AT_STRINGS_END(d+1))
	  break;
	goto fail;

	/* `or' constructs are handled by starting each alternative with
	   an on_failure_jump that points to the start of the next
	   alternative.  Each alternative except the last ends with a
	   jump to the joining point.  (Actually, each jump except for
	   the last one really jumps to the following jump, because
	   tensioning the jumps is a hassle.)  */

	/* The start of a stupid repeat has an on_failure_jump that points
	   past the end of the repeat text. This makes a failure point so 
	   that on failure to match a repetition, matching restarts past
	   as many repetitions have been found with no way to fail and
	   look for another one.  */

	/* A smart repeat is similar but loops back to the on_failure_jump
	   so that each repetition makes another failure point.  */

	/* Match at the starting position. */
      case begpos:
	if (d - string == beg)
	  break;
	goto fail;

      case on_failure_jump:
      on_failure:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      PUSH_FAILURE_POINT(p + mcnt, d);
      continue;

      /* The end of a smart repeat has a maybe_finalize_jump back.
	 Change it either to a finalize_jump or an ordinary jump.  */
      case maybe_finalize_jump:
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	p1 = p;

	/* Compare the beginning of the repeat with what in the
	   pattern follows its end. If we can establish that there
	   is nothing that they would both match, i.e., that we
	   would have to backtrack because of (as in, e.g., `a*a')
	   then we can change to finalize_jump, because we'll
	   never have to backtrack.

	   This is not true in the case of alternatives: in
	   `(a|ab)*' we do need to backtrack to the `ab' alternative
	   (e.g., if the string was `ab').  But instead of trying to
	   detect that here, the alternative has put on a dummy
	   failure point which is what we will end up popping.  */

	/* Skip over open/close-group commands.  */
	while (p1 + 2 < pend) {
	  if ((enum regexpcode)*p1 == stop_memory ||
	      (enum regexpcode)*p1 == start_memory)
	    p1 += 3;	/* Skip over args, too.  */
	  else if (/*(enum regexpcode)*p1 == start_paren ||*/
		   (enum regexpcode)*p1 == stop_paren)
	      p1 += 1;
	  else
	    break;
	}

	if (p1 == pend)
	  p[-3] = (unsigned char)finalize_jump;
	else if (*p1 == (unsigned char)exactn ||
		 *p1 == (unsigned char)endline) {
	  register int c = *p1 == (unsigned char)endline ? '\n' : p1[2];
	  register unsigned char *p2 = p + mcnt;
	    /* p2[0] ... p2[2] are an on_failure_jump.
	       Examine what follows that.  */
	  if (p2[3] == (unsigned char)exactn && p2[5] != c)
	    p[-3] = (unsigned char)finalize_jump;
	  else if (p2[3] == (unsigned char)charset ||
		   p2[3] == (unsigned char)charset_not) {
	    int not;
	    if (ismbchar(c)) {
	      unsigned char *pp = p1+3;
	      MBC2WC(c, pp);
	    }
	    /* `is_in_list()' is TRUE if c would match */
	    /* That means it is not safe to finalize.  */
	    not = is_in_list(c, p2 + 4);
	    if (p2[3] == (unsigned char)charset_not)
	      not = !not;
	    if (!not)
	      p[-3] = (unsigned char)finalize_jump;
	  }
	}
	p -= 2;		/* Point at relative address again.  */
	if (p[-1] != (unsigned char)finalize_jump) {
	  p[-1] = (unsigned char)jump;	
	  goto nofinalize;
	}
	/* Note fall through.  */

	/* The end of a stupid repeat has a finalize_jump back to the
	   start, where another failure point will be made which will
	   point to after all the repetitions found so far.  */

	/* Take off failure points put on by matching on_failure_jump 
	   because didn't fail.  Also remove the register information
	   put on by the on_failure_jump.  */
      case finalize_jump:
	if (stackp > stackb && stackp[-3] == d) {
	  p = stackp[-4];
	  POP_FAILURE_POINT();
	  continue;
	}
	POP_FAILURE_POINT(); 
	/* Note fall through.  */

      /* We need this opcode so we can detect where alternatives end
	 in `group_match_null_string_p' et al.  */
      case jump_past_alt:
	/* fall through */

	/* Jump without taking off any failure points.  */
      case jump:
      nofinalize:
        EXTRACT_NUMBER_AND_INCR(mcnt, p);
        if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */
	   goto fail;
        p += mcnt;
        continue;

      case dummy_failure_jump:
	/* Normally, the on_failure_jump pushes a failure point, which
	   then gets popped at finalize_jump.  We will end up at
	   finalize_jump, also, and with a pattern of, say, `a+', we
	   are skipping over the on_failure_jump, so we have to push
	   something meaningless for finalize_jump to pop.  */
	PUSH_FAILURE_POINT(0, 0);
	goto nofinalize;

	/* At the end of an alternative, we need to push a dummy failure
	   point in case we are followed by a `finalize_jump', because
	   we don't want the failure point for the alternative to be
	   popped.  For example, matching `(a|ab)*' against `aab'
	   requires that we match the `ab' alternative.  */
      case push_dummy_failure:
	/* See comments just above at `dummy_failure_jump' about the
	   two zeroes.  */
	p1 = p;
	/* Skip over open/close-group commands.  */
	while (p1 + 2 < pend) {
	  if ((enum regexpcode)*p1 == stop_memory ||
	      (enum regexpcode)*p1 == start_memory)
	    p1 += 3;	/* Skip over args, too.  */
	  else if (/*(enum regexpcode)*p1 == start_paren ||*/
		   (enum regexpcode)*p1 == stop_paren)
	      p1 += 1;
	  else
	    break;
	}
	if (p1 < pend && (enum regexpcode)*p1 == jump)
	  p[-1] = unused;
	else
	  PUSH_FAILURE_POINT(0, 0);
	break;

	/* Have to succeed matching what follows at least n times.  Then
	   just handle like an on_failure_jump.  */
      case succeed_n: 
	EXTRACT_NUMBER(mcnt, p + 2);
	/* Originally, this is how many times we HAVE to succeed.  */
	if (mcnt != 0) {
	  mcnt--;
	  p += 2;
	  PUSH_FAILURE_COUNT(p);
	  STORE_NUMBER_AND_INCR(p, mcnt);
	  PUSH_FAILURE_POINT(0, 0);
	}
	else  {
	  goto on_failure;
	}
	continue;

      case jump_n:
	EXTRACT_NUMBER(mcnt, p + 2);
	/* Originally, this is how many times we CAN jump.  */
	if (mcnt) {
	  mcnt--;
	  PUSH_FAILURE_COUNT(p + 2);
	  STORE_NUMBER(p + 2, mcnt);
	  goto nofinalize;	     /* Do the jump without taking off
					any failure points.  */
	}
	/* If don't have to jump any more, skip over the rest of command.  */
	else      
	  p += 4;		     
	continue;

      case set_number_at:
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	p1 = p + mcnt;
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	STORE_NUMBER(p1, mcnt);
	continue;

      case try_next:
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	if (p + mcnt < pend) {
	  PUSH_FAILURE_POINT(p, d);
	  stackp[-1] = NON_GREEDY;
	}
	p += mcnt;
	continue;

      case finalize_push:
	POP_FAILURE_POINT();
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
        if (mcnt < 0 && stackp > stackb  && stackp[-3] == d) /* avoid infinite loop */
	   goto fail;
	PUSH_FAILURE_POINT(p + mcnt, d);
	stackp[-1] = NON_GREEDY;
	continue;

      case finalize_push_n:
	EXTRACT_NUMBER(mcnt, p + 2); 
	/* Originally, this is how many times we CAN jump.  */
	if (mcnt) {
	  int pos, i;

	  mcnt--;
	  STORE_NUMBER(p + 2, mcnt);
	  EXTRACT_NUMBER(pos, p);
	  EXTRACT_NUMBER(i, p+pos+5);
	  if (i > 0) goto nofinalize;
	  POP_FAILURE_POINT();
	  EXTRACT_NUMBER_AND_INCR(mcnt, p);
	  PUSH_FAILURE_POINT(p + mcnt, d);
	  stackp[-1] = NON_GREEDY;
	  p += 2;		/* skip n */
	}
	/* If don't have to push any more, skip over the rest of command.  */
	else 
	  p += 4;   
	continue;

	/* Ignore these.  Used to ignore the n of succeed_n's which
	   currently have n == 0.  */
      case unused:
	continue;

      case casefold_on:
	options |= RE_OPTION_IGNORECASE;
	continue;

      case casefold_off:
	options &= ~RE_OPTION_IGNORECASE;
	continue;

      case option_set:
	options = *p++;
	continue;

      case wordbound:
	if (AT_STRINGS_BEG(d)) {
	  if (AT_STRINGS_END(d)) goto fail;
	  if (IS_A_LETTER(d)) break;
	  else goto fail;
	}
	if (AT_STRINGS_END(d)) {
	  if (PREV_IS_A_LETTER(d)) break;
	  else goto fail;
	}
	if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d))
	  break;
	goto fail;

      case notwordbound:
	if (AT_STRINGS_BEG(d)) {
	  if (IS_A_LETTER(d)) goto fail;
	  else break;
	}
	if (AT_STRINGS_END(d)) {
	  if (PREV_IS_A_LETTER(d)) goto fail;
	  else break;
	}
	if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d))
	  goto fail;
	break;

      case wordbeg:
	if (IS_A_LETTER(d) && (AT_STRINGS_BEG(d) || !PREV_IS_A_LETTER(d)))
	  break;
	goto fail;

      case wordend:
	if (!AT_STRINGS_BEG(d) && PREV_IS_A_LETTER(d)
	    && (!IS_A_LETTER(d) || AT_STRINGS_END(d)))
	  break;
	goto fail;

      case wordchar:
	PREFETCH;
	if (!IS_A_LETTER(d))
	  goto fail;
	if (ismbchar(*d) && d + mbclen(*d) - 1 < dend)
	  d += mbclen(*d) - 1;
	d++;
	SET_REGS_MATCHED;
	break;

      case notwordchar:
	PREFETCH;
	if (IS_A_LETTER(d))
	  goto fail;
	if (ismbchar(*d) && d + mbclen(*d) - 1 < dend)
	  d += mbclen(*d) - 1;
	d++;
	SET_REGS_MATCHED;
	break;

      case exactn:
	/* Match the next few pattern characters exactly.
	   mcnt is how many characters to match.  */
	mcnt = *p++;
	/* This is written out as an if-else so we don't waste time
	   testing `translate' inside the loop.  */
	if (TRANSLATE_P()) {
	  do {
	    unsigned char c;

	    PREFETCH;
	    if (*p == 0xff) {
	      p++;  
	      if (!--mcnt
		  || AT_STRINGS_END(d)
		  || (unsigned char)*d++ != (unsigned char)*p++)
		goto fail;
	      continue;
	    }
	    c = *d++;
	    if (ismbchar(c)) {
	      int n;

	      if (c != (unsigned char)*p++)
		goto fail;
	      for (n = mbclen(c) - 1; n > 0; n--)
		if (!--mcnt	/* redundant check if pattern was
				   compiled properly. */
		    || AT_STRINGS_END(d)
		    || (unsigned char)*d++ != (unsigned char)*p++)
		  goto fail;
	      continue;
	    }
	    /* compiled code translation needed for ruby */
	    if ((unsigned char)translate[c] != (unsigned char)translate[*p++])
	      goto fail;
	  }
	  while (--mcnt);
	}
	else {
	  do {
	    PREFETCH;
	    if (*p == 0xff) {p++; mcnt--;}
	    if (*d++ != *p++) goto fail;
	  }
	  while (--mcnt);
	}
	SET_REGS_MATCHED;
	break;
      }
#ifdef RUBY
    CHECK_INTS;
#endif
    continue;  /* Successfully executed one pattern command; keep going.  */

    /* Jump here if any matching operation fails. */
  fail:
    if (stackp != stackb) {
      /* A restart point is known.  Restart there and pop it. */
      short last_used_reg, this_reg;

      /* If this failure point is from a dummy_failure_point, just
	 skip it.  */
      if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) {
	POP_FAILURE_POINT();
	goto fail;
      }
      stackp--;		/* discard greedy flag */
      options = (long)*--stackp;
      d = *--stackp;
      p = *--stackp;
      /* Restore register info.  */
      last_used_reg = (long)*--stackp;

      /* Make the ones that weren't saved -1 or 0 again. */
      for (this_reg = num_regs - 1; this_reg > last_used_reg; this_reg--) {
	regend[this_reg] = REG_UNSET_VALUE;
	regstart[this_reg] = REG_UNSET_VALUE;
	IS_ACTIVE(reg_info[this_reg]) = 0;
	MATCHED_SOMETHING(reg_info[this_reg]) = 0;
      }

      /* And restore the rest from the stack.  */
      for ( ; this_reg > 0; this_reg--) {
	reg_info[this_reg].word = *--stackp;
	regend[this_reg] = *--stackp;
	regstart[this_reg] = *--stackp;
      }
      mcnt = (long)*--stackp;
      while (mcnt--) {
	POP_FAILURE_COUNT();
      }
      if (p < pend) {
	int is_a_jump_n = 0;
	int failed_paren = 0;

	p1 = p;
	/* If failed to a backwards jump that's part of a repetition
	   loop, need to pop this failure point and use the next one.  */
	switch ((enum regexpcode)*p1) {
	case jump_n:
	case finalize_push_n:
	  is_a_jump_n = 1;
	case maybe_finalize_jump:
	case finalize_jump:
	case finalize_push:
	case jump:
	  p1++;
	  EXTRACT_NUMBER_AND_INCR(mcnt, p1);

	  if (mcnt >= 0) break;	/* should be backward jump */
	  p1 += mcnt;

	  if (( is_a_jump_n && (enum regexpcode)*p1 == succeed_n) ||
	      (!is_a_jump_n && (enum regexpcode)*p1 == on_failure_jump)) {
	    if (failed_paren) {
	      p1++;
	      EXTRACT_NUMBER_AND_INCR(mcnt, p1);
	      PUSH_FAILURE_POINT(p1 + mcnt, d);
	    }
	    goto fail;
	  }
	  break;
	default:
	  /* do nothing */;
	}
      }
    }
    else
      break;   /* Matching at this starting point really fails.  */
  }

  if (best_regs_set)
    goto restore_best_regs;

  FREE_AND_RETURN(stackb,(-1)); 	/* Failure to match.  */
}
