ned char)(((c) >>24) & 0xff);			\
    (p)[1] = (unsigned char)(((c) >>16) & 0xff);			\
    (p)[2] = (unsigned char)(((c) >> 8) & 0xff);			\
    (p)[3] = (unsigned char)(((c) >> 0) & 0xff);			\
  } while (0)

#define STORE_MBC_AND_INCR(p, c) 					\
  do {									\
    *(p)++ = (unsigned char)(((c) >>24) & 0xff);			\
    *(p)++ = (unsigned char)(((c) >>16) & 0xff);			\
    *(p)++ = (unsigned char)(((c) >> 8) & 0xff);			\
    *(p)++ = (unsigned char)(((c) >> 0) & 0xff);			\
  } while (0)

#define EXTRACT_MBC(p) 							\
  ((unsigned int)((unsigned char)(p)[0] << 24 |				\
		    (unsigned char)(p)[1] << 16 |			\
                    (unsigned char)(p)[2] <<  8 |			\
		    (unsigned char)(p)[3]))

#define EXTRACT_MBC_AND_INCR(p) 					\
  ((unsigned int)((p) += 4, 						\
		    (unsigned char)(p)[-4] << 24 |			\
		    (unsigned char)(p)[-3] << 16 |			\
                    (unsigned char)(p)[-2] <<  8 |			\
		    (unsigned char)(p)[-1]))

#define EXTRACT_UNSIGNED(p) \
  ((unsigned char)(p)[0] | (unsigned char)(p)[1] << 8)
#define EXTRACT_UNSIGNED_AND_INCR(p) \
  ((p) += 2, (unsigned char)(p)[-2] | (unsigned char)(p)[-1] << 8)

/* Handle (mb)?charset(_not)?.

   Structure of mbcharset(_not)? in compiled pattern.

     struct {
       unsinged char id;		mbcharset(_not)?
       unsigned char sbc_size;
       unsigned char sbc_map[sbc_size];	same as charset(_not)? up to here.
       unsigned short mbc_size;		number of intervals.
       struct {
	 unsigned long beg;		beginning of interval.
	 unsigned long end;		end of interval.
       } intervals[mbc_size];
     }; */

static void
set_list_bits(c1, c2, b)
    unsigned long c1, c2;
    unsigned char *b;
{
  unsigned char sbc_size = b[-1];
  unsigned short mbc_size = EXTRACT_UNSIGNED(&b[sbc_size]);
  unsigned short beg, end, upb;

  if (c1 > c2)
    return;
  b = &b[sbc_size + 2];

  for (beg = 0, upb = mbc_size; beg < upb; ) {
    unsigned short mid = (unsigned short)(beg + upb) >> 1;

    if ((int)c1 - 1 > (int)EXTRACT_MBC(&b[mid*8+4]))
      beg = mid + 1;
    else
      upb = mid;
  }

  for (end = beg, upb = mbc_size; end < upb; ) {
    unsigned short mid = (unsigned short)(end + upb) >> 1;

    if ((int)c2 >= (int)EXTRACT_MBC(&b[mid*8]) - 1)
      end = mid + 1;
    else
      upb = mid;
  }

  if (beg != end) {
    if (c1 > EXTRACT_MBC(&b[beg*8]))
      c1 = EXTRACT_MBC(&b[beg*8]);
    if (c2 < EXTRACT_MBC(&b[(end - 1)*8+4]))
      c2 = EXTRACT_MBC(&b[(end - 1)*8+4]);
  }
  if (end < mbc_size && end != beg + 1)
    /* NOTE: memcpy() would not work here.  */
    memmove(&b[(beg + 1)*8], &b[end*8], (mbc_size - end)*8);
  STORE_MBC(&b[beg*8 + 0], c1);
  STORE_MBC(&b[beg*8 + 4], c2);
  mbc_size += beg - end + 1;
  STORE_NUMBER(&b[-2], mbc_size);
}

static int
is_in_list(c, b)
    unsigned long c;
    const unsigned char *b;
{
  unsigned short size;
  unsigned short i, j;

  size = *b++;
  if ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH) {
    return 1;
  }
  b += size + 2;
  size = EXTRACT_UNSIGNED(&b[-2]);
  if (size == 0) return 0;

  for (i = 0, j = size; i < j; ) {
    unsigned short k = (unsigned short)(i + j) >> 1;

    if (c > EXTRACT_MBC(&b[k*8+4]))
      i = k + 1;
    else
      j = k;
  }
  if (i < size && EXTRACT_MBC(&b[i*8]) <= c)
    return 1;
  return 0;
}

static void
print_partial_compiled_pattern(start, end)
    unsigned char *start;
    unsigned char *end;
{
  int mcnt, mcnt2;
  unsigned char *p = start;
  unsigned char *pend = end;

  if (start == NULL) {
    printf("(null)\n");
    return;
  }

  /* Loop over pattern commands.  */
  while (p < pend) {
    switch ((enum regexpcode)*p++) {
    case unused:
      printf("/unused");
      break;

    case exactn:
      mcnt = *p++;
      printf("/exactn/%d", mcnt);
      do {
	putchar('/');
	printf("%c", *p++);
      }
      while (--mcnt);
      break;

    case start_memory:
      mcnt = *p++;
      printf("/start_memory/%d/%d", mcnt, *p++);
      break;

    case stop_memory:
      mcnt = *p++;
      printf("/stop_memory/%d/%d", mcnt, *p++);
      break;

    case start_paren:
      printf("/start_paren");
      break;

    case stop_paren:
      printf("/stop_paren");
      break;

    case casefold_on:
      printf("/casefold_on");
      break;

    case casefold_off:
      printf("/casefold_off");
      break;

    case option_set:
      printf("/option_set/%d", *p++);
      break;

    case start_nowidth:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/start_nowidth//%d", mcnt);
      break;

    case stop_nowidth:
      printf("/stop_nowidth//");
      p += 2;
      break;

    case pop_and_fail:
      printf("/pop_and_fail");
      break;

    case stop_backtrack:
      printf("/stop_backtrack//");
      p += 2;
      break;

    case duplicate:
      printf("/duplicate/%d", *p++);
      break;

    case anychar:
      printf("/anychar");
      break;

    case anychar_repeat:
      printf("/anychar_repeat");
      break;

    case charset:
    case charset_not:
      {
	register int c;

	printf("/charset%s",
	       (enum regexpcode)*(p - 1) == charset_not ? "_not" : "");

	mcnt = *p++;
	printf("/%d", mcnt);
	for (c = 0; c < mcnt; c++) {
	  unsigned bit;
	  unsigned char map_byte = p[c];

	  putchar ('/');

	  for (bit = 0; bit < BYTEWIDTH; bit++)
	    if (map_byte & (1 << bit))
	      printf("%c", c * BYTEWIDTH + bit);
	}
	p += mcnt;
	mcnt = EXTRACT_UNSIGNED_AND_INCR(p);
	printf("/");
	while (mcnt--) {
	  print_mbc(EXTRACT_MBC_AND_INCR(p));
	  printf("-");
	  print_mbc(EXTRACT_MBC_AND_INCR(p));
	}
	break;
      }

    case begline:
      printf("/begline");
      break;

    case endline:
      printf("/endline");
      break;

    case on_failure_jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/on_failure_jump//%d", mcnt);
      break;

    case dummy_failure_jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/dummy_failure_jump//%d", mcnt);
      break;

    case push_dummy_failure:
      printf("/push_dummy_failure");
      break;

    case finalize_jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/finalize_jump//%d", mcnt);
      break;

    case maybe_finalize_jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/maybe_finalize_jump//%d", mcnt);
      break;

    case jump_past_alt:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/jump_past_alt//%d", mcnt);
      break;

    case jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/jump//%d", mcnt);
      break;

    case succeed_n: 
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      EXTRACT_NUMBER_AND_INCR(mcnt2, p);
      printf("/succeed_n//%d//%d", mcnt, mcnt2);
      break;

    case jump_n: 
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      EXTRACT_NUMBER_AND_INCR(mcnt2, p);
      printf("/jump_n//%d//%d", mcnt, mcnt2);
      break;

    case set_number_at: 
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      EXTRACT_NUMBER_AND_INCR(mcnt2, p);
      printf("/set_number_at//%d//%d", mcnt, mcnt2);
      break;

    case try_next:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/try_next//%d", mcnt);
      break;

    case finalize_push:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      printf("/finalize_push//%d", mcnt);
      break;

    case finalize_push_n:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      EXTRACT_NUMBER_AND_INCR(mcnt2, p);
      printf("/finalize_push_n//%d//%d", mcnt, mcnt2);
      break;

    case wordbound:
      printf("/wordbound");
      break;

    case notwordbound:
      printf("/notwordbound");
      break;

    case wordbeg:
      printf("/wordbeg");
      break;

    case wordend:
      printf("/wordend");

    case wordchar:
      printf("/wordchar");
      break;
	  
    case notwordchar:
      printf("/notwordchar");
      break;

    case begbuf:
      printf("/begbuf");
      break;

    case endbuf:
      printf("/endbuf");
      break;

    case endbuf2:
      printf("/endbuf2");
      break;

    case begpos:
      printf("/begpos");
      break;

    default:
      printf("?%d", *(p-1));
    }
  }
  printf("/\n");
}


static void
print_compiled_pattern(bufp)
     struct re_pattern_buffer *bufp;
{
  unsigned char *buffer = (unsigned char*)bufp->buffer;

  print_partial_compiled_pattern(buffer, buffer + bufp->used);
}

static char*
calculate_must_string(start, end)
     char *start;
     char *end;
{
  int mcnt;
  int max = 0;
  char *p = start;
  char *pend = end;
  char *must = 0;

  if (start == NULL) return 0;

  /* Loop over pattern commands.  */
  while (p < pend) {
    switch ((enum regexpcode)*p++) {
    case unused:
      break;

    case exactn:
      mcnt = *p;
      if (mcnt > max) {
	must = p;
	max = mcnt;
      }
      p += mcnt+1;
      break;

    case start_memory:
    case stop_memory:
      p += 2;
      break;

    case duplicate:
      p++;
      break;

    case casefold_on:
    case casefold_off:
      return 0;		/* should not check must_string */

    case pop_and_fail:
    case anychar:
    case anychar_repeat:
    case begline:
    case endline:
    case wordbound:
    case notwordbound:
    case wordbeg:
    case wordend:
    case wordchar:
    case notwordchar:
    case begbuf:
    case endbuf:
    case endbuf2:
    case begpos:
    case push_dummy_failure:
    case start_paren:
    case stop_paren:
    case option_set:
      break;

    case charset:
    case charset_not:
      mcnt = *p++;
      p += mcnt;
      mcnt = EXTRACT_UNSIGNED_AND_INCR(p);
      while (mcnt--) {
	p += 8;
      }
      break;

    case on_failure_jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      if (mcnt > 0) p += mcnt;
      if ((enum regexpcode)p[-3] == jump) {
       p -= 2;
	EXTRACT_NUMBER_AND_INCR(mcnt, p);
	if (mcnt > 0) p += mcnt;
      }
      break;

    case dummy_failure_jump:
    case succeed_n: 
    case try_next:
    case jump:
      EXTRACT_NUMBER_AND_INCR(mcnt, p);
      if (mcnt > 0) p += mcnt;
      break;

    case start_nowidth:
    case stop_nowidth:
    case stop_backtrack:
    case finalize_jump:
    case maybe_finalize_jump:
    case finalize_push:
      p += 2;
      break;

    case jump_n: 
    case set_number_at: 
    case finalize_push_n:
      p += 4;
      break;

    default:
      break;
    }
  }
  return must;
}

static unsigned int
read_backslash(c)
     int c;
{
  switch (c) {
  case 'n':
    return '\n';

  case 't':
    return '\t';

  case 'r':
    return '\r';

  case 'f':
    return '\f';

  case 'v':
    return '\v';

  case 'a':
    return '\007';

  case 'b':
    return '\010';

  case 'e':
    return '\033';
  }
  return c;
}

static unsigned int
read_special(p, pend, pp)
     const char *p, *pend, **pp;
{
  int c;

  PATFETCH_RAW(c);
  switch (c) {
  case 'M':
    PATFETCH_RAW(c);
    if (c != '-') return -1;
    PATFETCH_RAW(c);
    *pp = p;
    if (c == '\\') {
      return read_special(p, pend, pp) | 0x80;
    }
    else if (c == -1) return ~0;
    else {
      return ((c & 0xff) | 0x80);
    }

  case 'C':
    PATFETCH_RAW(c);
    if (c != '-') return ~0;
  case 'c':
    PATFETCH_RAW(c);
    *pp = p;
    if (c == '\\') {
      c = read_special(p, pend, pp);
    }
    else if (c == '?') return 0177;
    else if (c == -1) return ~0;
    return c & 0x9f;
  default:
    return read_backslash(c);
  }

 end_of_pattern:
  return ~0;
}

/* re_compile_pattern takes a regular-expression string
   and converts it into a buffer full of byte commands for matching.

   PATTERN   is the address of the pattern string
   SIZE      is the length of it.
   BUFP	    is a  struct re_pattern_buffer *  which points to the info
	     on where to store the byte commands.
	     This structure contains a  char *  which points to the
	     actual space, which should have been obtained with malloc.
	     re_compile_pattern may use realloc to grow the buffer space.

   The number of bytes of commands can be found out by looking in
   the `struct re_pattern_buffer' that bufp pointed to, after
   re_compile_pattern returns. */

char *
re_compile_pattern(pattern, size, bufp)
     const char *pattern;
     int size;
     struct re_pattern_buffer *bufp;
{
  register char *b = bufp->buffer;
  register const char *p = pattern;
  const char *nextp;
  const char *pend = pattern + size;
  register unsigned int c, c1 = 0;
  const char *p0;
  int numlen;
#define ERROR_MSG_MAX_SIZE 200
  static char error_msg[ERROR_MSG_MAX_SIZE+1];

  /* Address of the count-byte of the most recently inserted `exactn'
     command.  This makes it possible to tell whether a new exact-match
     character can be added to that command or requires a new `exactn'
     command.  */

  char *pending_exact = 0;

  /* Address of the place where a forward-jump should go to the end of
     the containing expression.  Each alternative of an `or', except the
     last, ends with a forward-jump of this sort.  */

  char *fixup_alt_jump = 0;

  /* Address of start of the most recently finished expression.
     This tells postfix * where to find the start of its operand.  */

  char *laststart = 0;

  /* In processing a repeat, 1 means zero matches is allowed.  */

  char zero_times_ok;

  /* In processing a repeat, 1 means many matches is allowed.  */

  char many_times_ok;

  /* In processing a repeat, 1 means non-greedy matches.  */

  char greedy;

  /* Address of beginning of regexp, or inside of last (.  */

  char *begalt = b;

  /* Place in the uncompiled pattern (i.e., the {) to
     which to go back if the interval is invalid.  */
  const char *beg_interval;

  /* In processing an interval, at least this many matches must be made.  */
  int lower_bound;

  /* In processing an interval, at most this many matches can be made.  */
  int upper_bound;

  /* Stack of information saved by ( and restored by ).
     Five stack elements are pushed by each (:
     First, the value of b.
     Second, the value of fixup_alt_jump.
     Third, the value of begalt.
     Fourth, the value of regnum.
     Fifth, the type of the paren. */

  int stacka[40];
  int *stackb = stacka;
  int *stackp = stackb;
  int *stacke = stackb + 40;

  /* Counts ('s as they are encountered.  Remembered for the matching ),
     where it becomes the register number to put in the stop_memory
     command.  */

  int regnum = 1;

  int range = 0;
  int had_mbchar = 0;
  int had_num_literal = 0;
  int had_char_class = 0;

  int options = bufp->options;

  bufp->fastmap_accurate = 0;
  bufp->must = 0;
  bufp->must_skip = 0;

  /* Initialize the syntax table.  */
  init_syntax_once();

  if (bufp->allocated == 0) {
    bufp->allocated = INIT_BUF_SIZE;
    if (bufp->buffer)
      /* EXTEND_BUFFER loses when bufp->allocated is 0.  */
      bufp->buffer = (char*)xrealloc(bufp->buffer, INIT_BUF_SIZE);
    else
      /* Caller did not allocate a buffer.  Do it for them.  */
      bufp->buffer = (char*)xmalloc(INIT_BUF_SIZE);
    if (!bufp->buffer) goto memory_exhausted;
    begalt = b = bufp->buffer;
  }

  while (p != pend) {
    PATFETCH(c);

    switch (c) {
    case '$':
      if (bufp->options & RE_OPTION_SINGLELINE) {
	BUFPUSH(endbuf);
      }
      else {
	p0 = p;
	/* When testing what follows the $,
	   look past the \-constructs that don't consume anything.  */

	while (p0 != pend) {
	  if (*p0 == '\\' && p0 + 1 != pend
	      && (p0[1] == 'b' || p0[1] == 'B'))
	    p0 += 2;
	  else
	    break;
	}
	BUFPUSH(endline);
      }
      break;

    case '^':
      if (bufp->options & RE_OPTION_SINGLELINE)
	BUFPUSH(begbuf);
      else
	BUFPUSH(begline);
      break;

    case '+':
    case '?':
    case '*':
      /* If there is no previous pattern, char not special. */
      if (!laststart) {
	snprintf(error_msg, ERROR_MSG_MAX_SIZE, 
		 "invalid regular expression; there's no previous pattern, to which '%c' would define cardinality at %d", 
		 c, p-pattern);
	FREE_AND_RETURN(stackb, error_msg);
      }
      /* If there is a sequence of repetition chars,
	 collapse it down to just one.  */
      zero_times_ok = c != '+';
      many_times_ok = c != '?';
      greedy = 1;
      if (p != pend) {
	PATFETCH(c);
	switch (c) {
	case '?':
	  greedy = 0;
	  break;
	case '*':
	case '+':
	  goto nested_meta;
	default:
	  PATUNFETCH;
	  break;
	}
      }

    repeat:
      /* Star, etc. applied to an empty pattern is equivalent
	 to an empty pattern.  */
      if (!laststart)  
	break;

      if (greedy && many_times_ok && *laststart == anychar && b - laststart <= 2) {
	if (b[-1] == stop_paren)
	  b--;
	if (zero_times_ok)
	  *laststart = anychar_repeat;
	else {
	  BUFPUSH(anychar_repeat);
	}
	break;
      }
      /* Now we know whether or not zero matches is allowed
	 and also whether or not two or more matches is allowed.  */
      if (many_times_ok) {
	/* If more than one repetition is allowed, put in at the
	   end a backward relative jump from b to before the next
	   jump we're going to put in below (which jumps from
	   laststart to after this jump).  */
	GET_BUFFER_SPACE(3);
	store_jump(b,greedy?maybe_finalize_jump:finalize_push,laststart-3);
	b += 3;  	/* Because store_jump put stuff here.  */
      }

      /* On failure, jump from laststart to next pattern, which will be the
	 end of the buffer after this jump is inserted.  */
      GET_BUFFER_SPACE(3);
      insert_jump(on_failure_jump, laststart, b + 3, b);
      b += 3;

      if (zero_times_ok) {
	if (greedy == 0) {
	  GET_BUFFER_SPACE(3);
	  insert_jump(try_next, laststart, b + 3, b);
	  b += 3;
	}
      }
      else {
	/* At least one repetition is required, so insert a
	   `dummy_failure_jump' before the initial
	   `on_failure_jump' instruction of the loop. This
	   effects a skip over that instruction the first time
	   we hit that loop.  */
	GET_BUFFER_SPACE(3);
	insert_jump(dummy_failure_jump, laststart, laststart + 6, b);
	b += 3;
      }
      break;

    case '.':
      laststart = b;
      BUFPUSH(anychar);
      break;

    case '[':
      if (p == pend)
	FREE_AND_RETURN(stackb, "invalid regular expression; '[' can't be the last character ie. can't start range at the end of pattern");
      while ((b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH)
	     > bufp->allocated)
	EXTEND_BUFFER;

      laststart = b;
      if (*p == '^') {
	BUFPUSH(charset_not); 
	p++;
      }
      else
	BUFPUSH(charset);
      p0 = p;

      BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH);
      /* Clear the whole map */
      memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2);

      had_mbchar = 0;
      had_num_literal = 0;
      had_char_class = 0;

      /* Read in characters and ranges, setting map bits.  */
      for (;;) {
	int size;
	unsigned last = (unsigned)-1;

	if ((size = EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH]))
	    || current_mbctype) {
	  /* Ensure the space is enough to hold another interval
	     of multi-byte chars in charset(_not)?.  */
	  size = (1 << BYTEWIDTH) / BYTEWIDTH + 2 + size*8 + 8;
	  while (b + size + 1 > bufp->buffer + bufp->allocated)
	    EXTEND_BUFFER;
	}
      range_retry:
	if (range && had_char_class) {
	  FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as an end value of range");
	}
	PATFETCH(c);

	if (c == ']') {
	  if (p == p0 + 1) {
	    if (p == pend)
	      FREE_AND_RETURN(stackb, "invalid regular expression; empty character class");
	  }
	  else 
	    /* Stop if this isn't merely a ] inside a bracket
	       expression, but rather the end of a bracket
	       expression.  */
	    break;
	}
	/* Look ahead to see if it's a range when the last thing
	   was a character class.  */
	if (had_char_class && c == '-' && *p != ']')
	  FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as a start value of range");
	if (ismbchar(c)) {
	  PATFETCH_MBC(c);
	  had_mbchar++;
	}
	had_char_class = 0;

	/* \ escapes characters when inside [...].  */
	if (c == '\\') {
	  PATFETCH_RAW(c);
	  switch (c) {
	  case 'w':
	    for (c = 0; c < (1 << BYTEWIDTH); c++) {
	      if (SYNTAX(c) == Sword ||
		  (!current_mbctype && SYNTAX(c) == Sword2))
		SET_LIST_BIT(c);
	    }
	    if (current_mbctype) {
	      set_list_bits(0x80, 0xffffffff, b);
	    }
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 'W':
	    for (c = 0; c < (1 << BYTEWIDTH); c++) {
	      if (SYNTAX(c) != Sword &&
		  ((current_mbctype && !re_mbctab[c]) ||
		  (!current_mbctype && SYNTAX(c) != Sword2)))
		SET_LIST_BIT(c);
	    }
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 's':
	    for (c = 0; c < 256; c++)
	      if (ISSPACE(c))
		SET_LIST_BIT(c);
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 'S':
	    for (c = 0; c < 256; c++)
	      if (!ISSPACE(c))
		SET_LIST_BIT(c);
	    if (current_mbctype)
	      set_list_bits(0x80, 0xffffffff, b);
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 'd':
	    for (c = '0'; c <= '9'; c++)
	      SET_LIST_BIT(c);
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 'D':
	    for (c = 0; c < 256; c++)
	      if (!ISDIGIT(c))
		SET_LIST_BIT(c);
	    if (current_mbctype)
	      set_list_bits(0x80, 0xffffffff, b);
	    had_char_class = 1;
	    last = -1;
	    continue;

	  case 'x':
	    c = scan_hex(p, 2, &numlen);
	    if (numlen == 0) goto invalid_escape;
	    p += numlen;
	    had_num_literal = 1;
	    break;

	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9':
	    PATUNFETCH;
	    c = scan_oct(p, 3, &numlen);
	    p += numlen;
	    had_num_literal = 1;
	    break;

	  case 'M':
	  case 'C':
	  case 'c':
	    {
	      char *pp;

	      --p;
	      c = read_special(p, pend, &pp);
	      if (c > 255) goto invalid_escape;
	      p = pp;
	      had_num_literal = 1;
	    }
	    break;

	  default:
	    c = read_backslash(c);
	    if (ismbchar(c)) {
	      PATFETCH_MBC(c);
	      had_mbchar++;
	    }
	    break;
	  }
	}

	/* Get a range.  */
	if (range) {
	  if (last > c)
	    goto invalid_pattern;

	  range = 0;
	  if (had_mbchar == 0) {
	    for (;last<=c;last++)
	      SET_LIST_BIT(last);
	  }
	  else if (had_mbchar == 2) {
	    set_list_bits(last, c, b);
	  }
	  else {
	    /* restriction: range between sbc and mbc */
	    goto invalid_pattern;
	  }
	}
	else if (p[0] == '-' && p[1] != ']') {
	  last = c;
	  PATFETCH(c1);
	  range = 1;
	  goto range_retry;
	}
	else if (c == '[' && *p == ':') {
	  /* Leave room for the null.  */
	  char str[CHAR_CLASS_MAX_LENGTH + 1];

	  PATFETCH_RAW(c);
	  c1 = 0;

	  /* If pattern is `[[:'.  */
	  if (p == pend) 
	    FREE_AND_RETURN(stackb, "invalid regular expression; re can't end '[[:'");

	  for (;;) {
	    PATFETCH (c);
	    if (c == ':' || c == ']' || p == pend
		|| c1 == CHAR_CLASS_MAX_LENGTH)
	      break;
	    str[c1++] = c;
	  }
	  str[c1] = '\0';

	  /* If isn't a word bracketed by `[:' and:`]':
	     undo the ending character, the letters, and leave 
	     the leading `:' and `[' (but set bits for them).  */
	  if (c == ':' && *p == ']') {
	    int ch;
	    char is_alnum = STREQ(str, "alnum");
	    char is_alpha = STREQ(str, "alpha");
	    char is_blank = STREQ(str, "blank");
	    char is_cntrl = STREQ(str, "cntrl");
	    char is_digit = STREQ(str, "digit");
	    char is_graph = STREQ(str, "graph");
	    char is_lower = STREQ(str, "lower");
	    char is_print = STREQ(str, "print");
	    char is_punct = STREQ(str, "punct");
	    char is_space = STREQ(str, "space");
	    char is_upper = STREQ(str, "upper");
	    char is_xdigit = STREQ(str, "xdigit");

	    if (!IS_CHAR_CLASS(str)){
	      snprintf(error_msg, ERROR_MSG_MAX_SIZE, 
		       "invalid regular expression; [:%s:] is not a character class", str);
	      FREE_AND_RETURN(stackb, error_msg);
	    }

	    /* Throw away the ] at the end of the character class.  */
	    PATFETCH(c);

	    if (p == pend) 
	      FREE_AND_RETURN(stackb, "invalid regular expression; range doesn't have ending ']' after a character class");

	    for (ch = 0; ch < 1 << BYTEWIDTH; ch++) {
	      if (   (is_alnum  && ISALNUM(ch))
		  || (is_alpha  && ISALPHA(ch))
		  || (is_blank  && ISBLANK(ch))
		  || (is_cntrl  && ISCNTRL(ch))
		  || (is_digit  && ISDIGIT(ch))
		  || (is_graph  && ISGRAPH(ch))
		  || (is_lower  && ISLOWER(ch))
		  || (is_print  && ISPRINT(ch))
		  || (is_punct  && ISPUNCT(ch))
		  || (is_space  && ISSPACE(ch))
		  || (is_upper  && ISUPPER(ch))
		  || (is_xdigit && ISXDIGIT(ch)))
		SET_LIST_BIT(ch);
	    }
	    had_char_class = 1;
	  }
	  else {
	    c1++;
	    while (c1--)    
	      PATUNFETCH;
	    SET_LIST_BIT(TRANSLATE_P()?translate['[']:'[');
	    SET_LIST_BIT(TRANSLATE_P()?translate[':']:':');
	    had_char_class = 0;
	    last = ':';
	  }
	}
	else if (had_mbchar == 0 && (!current_mbctype || !had_num_literal)) {
	  SET_LIST_BIT(c);
	  had_num_literal = 0;
	}
	else
	  set_list_bits(c, c, b);
	had_mbchar = 0;
      }

      /* Discard any character set/class bitmap bytes that are all
	 0 at the end of the map. Decrement the map-length byte too.  */
      while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) 
	b[-1]--; 
      if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH)
	memmove(&b[b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH],
		2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8);
      b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[b[-1]])*8;
      break;

    case '(':
      {
	int old_options = options;
	int push_option = 0;
	int casefold = 0;

      PATFETCH(c);
      if (c == '?') {
	int negative = 0;

	PATFETCH_RAW(c);
	switch (c) {
	case 'x': case 'p': case 'm': case 'i': case '-':
	  for (;;) {
	    switch (c) {
	    case '-':
	      negative = 1;
	      break;

	    case ':':
	    case ')':
	      break;

	    case 'x':
	      if (negative)
		options &= ~RE_OPTION_EXTENDED;
	      else
		options |= RE_OPTION_EXTENDED;
	      break;

	    case 'p':
	      if (negative) {
		if ((options&RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) {
		  options &= ~RE_OPTION_POSIXLINE;
		}
	      }
	      else if ((options&RE_OPTION_POSIXLINE) != RE_OPTION_POSIXLINE) {
		options |= RE_OPTION_POSIXLINE;
	      }
	      push_option = 1;
	      break;

	    case 'm':
	      if (negative) {
		if (options&RE_OPTION_MULTILINE) {
		  options &= ~RE_OPTION_MULTILINE;
		}
	      }
	      else if (!(options&RE_OPTION_MULTILINE)) {
		options |= RE_OPTION_MULTILINE;
	      }
	      push_option = 1;
	      break;

	    case 'i':
	      if (negative) {
		if (options&RE_OPTION_IGNORECASE) {
		  options &= ~RE_OPTION_IGNORECASE;
		}
	      }
	      else if (!(options&RE_OPTION_IGNORECASE)) {
		options |= RE_OPTION_IGNORECASE;
	      }
		casefold = 1;
	      break;

	    default:
	      FREE_AND_RETURN(stackb, "undefined (?...) inline option");
	    }
	    if (c == ')') {
	      c = '#';	/* read whole in-line options */
	      break;
	    }
	    if (c == ':') break;
	    PATFETCH_RAW(c);
	  }
	  break;

	case '#':
	  for (;;) {
	    PATFETCH(c);
	    if (c == ')') break;
	  }
	  c = '#';
	  break;

	case ':':
	case '=':
	case '!':
	case '>':
	  break;

	default:
	  FREE_AND_RETURN(stackb, "undefined (?...) sequence");
	}
	}
	else {
	  PATUNFETCH;
	  c = '(';
	}
	if (c == '#') {
	if (push_option) {
	  BUFPUSH(option_set);
	  BUFPUSH(options);
	}
	  if (casefold) {
	    if (options & RE_OPTION_IGNORECASE)
	      BUFPUSH(casefold_on);
	    else
	      BUFPUSH(casefold_off);
      }
	  break;
      }
      if (stackp+8 >= stacke) {
	DOUBLE_STACK(int);
      }

      /* Laststart should point to the start_memory that we are about
	 to push (unless the pattern has RE_NREGS or more ('s).  */
      /* obsolete: now RE_NREGS is just a default register size. */
      *stackp++ = b - bufp->buffer;    
      *stackp++ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
      *stackp++ = begalt - bufp->buffer;
      switch (c) {
      case '(':
	BUFPUSH(start_memory);
	BUFPUSH(regnum);
	*stackp++ = regnum++;
	*stackp++ = b - bufp->buffer;
	BUFPUSH(0);
	/* too many ()'s to fit in a byte. (max 254) */
	if (regnum >= RE_REG_MAX) goto too_big;
	break;

      case '=':
      case '!':
      case '>':
	BUFPUSH(start_nowidth);
	*stackp++ = b - bufp->buffer;
	BUFPUSH(0);	/* temporary value */
	BUFPUSH(0);
	if (c != '!') break;

	BUFPUSH(on_failure_jump);
	*stackp++ = b - bufp->buffer;
	BUFPUSH(0