Пример #1
0
int
zmain (void)
{
  struct re_pattern_buffer r;
  size_t i;
  int ret = 0;

  for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i)
    {
      re_set_syntax (tests[i].syntax);
      memset (&r, 0, sizeof (r));
      if (re_compile_pattern (tests[i].regex, strlen (tests[i].regex), &r))
	{
	  printf ("re_compile_pattern %zd failed\n", i);
	  ret = 1;
	  continue;
	}
      size_t len = strlen (tests[i].string);
      int rv = re_search (&r, tests[i].string, len, 0, len, NULL);
      if (rv != tests[i].retval)
	{
	  printf ("re_search %zd unexpected value %d != %d\n",
		  i, rv, tests[i].retval);
	  ret = 1;
	}
      regfree (&r);
    }
  return ret;
}
Пример #2
0
int
main (void)
{
  setlocale (LC_ALL, "ja_JP.eucJP");

  re_set_syntax (RE_SYNTAX_SED);

  struct re_pattern_buffer re;
  memset (&re, 0, sizeof (re));

  struct re_registers regs;
  memset (&regs, 0, sizeof (regs));

  re_compile_pattern ("$", 1, &re);

  int ret = 0, r = re_search (&re, str1, 4, 0, 4, &regs);
  if (r != 4)
    {
      printf ("First re_search returned %d\n", r);
      ret = 1;
    }
  r = re_search (&re, str2, 4, 0, 4, &regs);
  if (r != 4)
    {
      printf ("Second re_search returned %d\n", r);
      ret = 1;
    }
  return ret;
}
Пример #3
0
static int
run_test_backwards (const char *expr, const char *mem, size_t memlen,
		    int icase, int expected)
{
  regex_t re;
  const char *err;
  size_t offset;
  int cnt;

  re_set_syntax ((RE_SYNTAX_POSIX_BASIC & ~RE_DOT_NEWLINE)
		 | RE_HAT_LISTS_NOT_NEWLINE
		 | (icase ? RE_ICASE : 0));

  memset (&re, 0, sizeof (re));
  re.fastmap = malloc (256);
  if (re.fastmap == NULL)
    error (EXIT_FAILURE, errno, "cannot allocate fastmap");

  err = re_compile_pattern (expr, strlen (expr), &re);
  if (err != NULL)
    error (EXIT_FAILURE, 0, "cannot compile expression: %s", err);

  if (re_compile_fastmap (&re))
    error (EXIT_FAILURE, 0, "couldn't compile fastmap");

  cnt = 0;
  offset = memlen;
  assert (mem[memlen] == '\0');
  while (offset <= memlen)
    {
      int start;
      const char *sp;
      const char *ep;

      start = re_search (&re, mem, memlen, offset, -offset, NULL);
      if (start == -1)
	break;

      if (start == -2)
	error (EXIT_FAILURE, 0, "internal error in re_search");

      sp = mem + start;
      while (sp > mem && sp[-1] != '\n')
	--sp;

      ep = mem + start;
      while (*ep != '\0' && *ep != '\n')
	++ep;

      printf ("match %d: \"%.*s\"\n", ++cnt, (int) (ep - sp), sp);

      offset = sp - 1 - mem;
    }

  regfree (&re);

  /* Return an error if the number of matches found is not match we
     expect.  */
  return cnt != expected;
}
Пример #4
0
int
zmain (void)
{
  struct re_pattern_buffer re;
  const char *s;
  int ret = 0;

  re_set_syntax (RE_SYNTAX_POSIX_EGREP);
  memset (&re, 0, sizeof (re));
  s = re_compile_pattern ("[[.invalid_collating_symbol.]]", 30, &re);
  if (s == NULL || strcmp (s, "Invalid collation character"))
    {
      printf ("re_compile_pattern returned %s\n", s);
      ret = 1;
    }
  s = re_compile_pattern ("[[=invalid_equivalence_class=]]", 31, &re);
  if (s == NULL || strcmp (s, "Invalid collation character"))
    {
      printf ("re_compile_pattern returned %s\n", s);
      ret = 1;
    }
  s = re_compile_pattern ("[[:invalid_character_class:]]", 29, &re);
  if (s == NULL || strcmp (s, "Invalid character class name"))
    {
      printf ("re_compile_pattern returned %s\n", s);
      ret = 1;
    }
  return ret;
}
Пример #5
0
Pattern
new_pattern(const char *pattern, int case_matters)
{
    int tpatlen = -1;
    const char *tpattern = translate_pattern(pattern, &tpatlen);
    regexp_t buf = mymalloc(sizeof(*buf), M_PATTERN);
    Pattern p;

    init_casefold_once();

    buf->buffer = 0;
    buf->allocated = 0;
    buf->translate = case_matters ? 0 : casefold;
    re_set_syntax(MOO_SYNTAX);

    if (tpattern
	&& !re_compile_pattern((void *) tpattern, tpatlen, buf)) {
	buf->fastmap = mymalloc(256 * sizeof(char), M_PATTERN);
	re_compile_fastmap(buf);
	p.ptr = buf;
    } else {
	if (buf->buffer)
	    free(buf->buffer);
	myfree(buf, M_PATTERN);
	p.ptr = 0;
    }

    return p;
}
Пример #6
0
static int compile_regex (lua_State *L, const TArgComp *argC, TGnu **pud) {
  const char *res;
  TGnu *ud;
  int ret;

  ud = (TGnu *)lua_newuserdata (L, sizeof (TGnu));
  memset (ud, 0, sizeof (TGnu));          /* initialize all members to 0 */

  re_set_syntax (argC->cflags);

  /* translate table is never written to, so this cast is safe */
  ud->r.translate = (unsigned char *) argC->translate;

  res = re_compile_pattern (argC->pattern, argC->patlen, &ud->r);
  if (res != NULL) {
      ud->errmsg = res;
      ret = generate_error (L, ud, 0);
  } else {
    lua_pushvalue (L, ALG_ENVIRONINDEX);
    lua_setmetatable (L, -2);

    if (pud) *pud = ud;
    ret = 1;
  }

  return ret;
}
Пример #7
0
static int
find_substr (astr as, const char *s2, size_t s2size, size_t from, size_t to,
             bool forward, bool notbol, bool noteol, bool regex, bool icase)
{
  int ret = -1;
  struct re_pattern_buffer pattern;
  struct re_registers search_regs;
  reg_syntax_t syntax = RE_SYNTAX_EMACS;

  memset (&pattern, 0, sizeof (pattern));

  if (!regex)
    syntax |= RE_PLAIN;
  if (icase)
    syntax |= RE_ICASE;
  re_set_syntax (syntax);
  search_regs.num_regs = 1;

  re_find_err = re_compile_pattern (s2, (int) s2size, &pattern);
  pattern.not_bol = notbol;
  pattern.not_eol = noteol;
  if (!re_find_err)
    ret = re_search (&pattern, astr_cstr (as), (int) astr_len (as), forward ? from : to - 1,
                     forward ? (to - from) : -(to - 1 - from), &search_regs);

  if (ret >= 0)
    {
      ret = forward ? search_regs.end[0] : ret;
      free (search_regs.start);
      free (search_regs.end);
    }

  regfree (&pattern);
  return ret;
}
Пример #8
0
int
main (void)
{
  struct re_pattern_buffer r;
  struct re_registers s;
  setlocale (LC_ALL, "en_US.UTF-8");
  memset (&r, 0, sizeof (r));
  memset (&s, 0, sizeof (s));
  re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | RE_ICASE);
  re_compile_pattern ("insert into", 11, &r);
  re_search (&r, "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK",
	     15, 0, 15, &s);
  return 0;
}
Пример #9
0
int
zmain (void)
{
  regex_t re;
  regmatch_t ma[2];
  int reerr;
  int res = 0;

  re_set_syntax (RE_DEBUG);
  reerr = regcomp (&re, "0*[0-9][0-9]", 0);
  if (reerr != 0)
    {
      char buf[100];
      regerror (reerr, &re, buf, sizeof buf);
      error (EXIT_FAILURE, 0, buf);
    }

  if (regexec (&re, "002", 2, ma, 0) != 0)
    {
      error (0, 0, "\"0*[0-9][0-9]\" does not match \"002\"");
      res = 1;
    }
  puts ("Succesful match with \"0*[0-9][0-9]\"");

  regfree (&re);

  reerr = regcomp (&re, "[0a]*[0-9][0-9]", 0);
  if (reerr != 0)
    {
      char buf[100];
      regerror (reerr, &re, buf, sizeof buf);
      error (EXIT_FAILURE, 0, buf);
    }

  if (regexec (&re, "002", 2, ma, 0) != 0)
    {
      error (0, 0, "\"[0a]*[0-9][0-9]\" does not match \"002\"");
      res = 1;
    }
  puts ("Succesful match with \"[0a]*[0-9][0-9]\"");

  regfree (&re);

  return res;
}
Пример #10
0
int
do_one_test (const struct test_s *test, const char *fail)
{
  int res;
  const char *err;
  struct re_pattern_buffer regbuf;

  re_set_syntax (test->syntax);
  memset (&regbuf, '\0', sizeof (regbuf));
  err = re_compile_pattern (test->pattern, strlen (test->pattern),
			    &regbuf);
  if (err != NULL)
    {
      printf ("%sre_compile_pattern \"%s\" failed: %s\n", fail, test->pattern,
	      err);
      return 1;
    }

  res = re_search (&regbuf, test->string, strlen (test->string),
		   test->start, strlen (test->string) - test->start, NULL);
  if (res != test->res)
    {
      printf ("%sre_search \"%s\" \"%s\" failed: %d (expected %d)\n",
	      fail, test->pattern, test->string, res, test->res);
      regfree (&regbuf);
      return 1;
    }

  if (test->res > 0 && test->start == 0)
    {
      res = re_search (&regbuf, test->string, strlen (test->string),
		       test->res, strlen (test->string) - test->res, NULL);
      if (res != test->res)
	{
	  printf ("%sre_search from expected \"%s\" \"%s\" failed: %d (expected %d)\n",
		  fail, test->pattern, test->string, res, test->res);
	  regfree (&regbuf);
	  return 1;
	}
    }

  regfree (&regbuf);
  return 0;
}
Пример #11
0
bool
Regexp::compile(vespalib::stringref re, Flags flags)
{
    re_set_syntax(flags.flags());
    regex_t *preg = (regex_t *)_data;
    preg->translate = NULL;
    preg->fastmap = static_cast<char *>(malloc(256));
    preg->buffer = NULL;
    preg->allocated = 0;
    const char * error = re_compile_pattern(re.data(), re.size(), preg);
    if (error != 0) {
        LOG(warning, "invalid regexp '%s': %s", vespalib::string(re).c_str(), error);
        return false;
    }
    if (re_compile_fastmap(preg) != 0) {
        LOG(warning, "re_compile_fastmap failed for regexp '%s'", vespalib::string(re).c_str());
        return false;
    }
    return true;
}
Пример #12
0
void
resetup()
{
	if (do_posix)
		syn = RE_SYNTAX_POSIX_AWK;	/* strict POSIX re's */
	else if (do_traditional)
		syn = RE_SYNTAX_AWK;		/* traditional Unix awk re's */
	else
		syn = RE_SYNTAX_GNU_AWK;	/* POSIX re's + GNU ops */

	/*
	 * Interval expressions are off by default, since it's likely to
	 * break too many old programs to have them on.
	 */
	if (do_intervals)
		syn |= RE_INTERVALS;

	(void) re_set_syntax(syn);
	dfasyntax(syn, FALSE, '\n');
}
Пример #13
0
int
main (void)
{
  struct re_pattern_buffer regbuf;
  const char *err;
  size_t i;
  int ret = 0;

#ifdef HAVE_MCHECK_H
  mtrace ();
#endif

  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
    {
      int start;
      re_set_syntax (tests[i].syntax);
      memset (&regbuf, '\0', sizeof (regbuf));
      err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
                                &regbuf);
      if (err != NULL)
	{
	  printf ("re_compile_pattern failed: %s\n", err);
	  ret = 1;
	  continue;
	}

      start = re_search (&regbuf, tests[i].string, strlen (tests[i].string),
                         0, strlen (tests[i].string), NULL);
      if (start != tests[i].start)
	{
	  printf ("re_search failed %d\n", start);
	  ret = 1;
	  regfree (&regbuf);
	  continue;
	}
      regfree (&regbuf);
    }

  return ret;
}
Пример #14
0
void
test_posix_extended ()
{
    /* Intervals can only match up to RE_DUP_MAX occurences of anything.  */
    char dup_max_plus_one[6];
    sprintf (dup_max_plus_one, "%d", RE_DUP_MAX + 1);


    printf ("\nStarting POSIX extended tests.\n");
    t = posix_extended_test;

    re_set_syntax (RE_SYNTAX_POSIX_MINIMAL_EXTENDED);

    test_posix_generic ();

    printf ("\nContinuing POSIX extended tests.\n");

    /* Grouping tests that differ from basic's.  */

    test_should_match = true;
    MATCH_SELF ("a)");

    /* Valid use of special characters.  */
    test_match ("\\(a", "(a");
    test_match ("a\\+", "a+");
    test_match ("a\\?", "a?");
    test_match ("\\{a", "{a");
    test_match ("\\|a", "|a");
    test_match ("a\\|b", "a|b");
    test_match ("a\\|?", "a");
    test_match ("a\\|?", "a|");
    test_match ("a\\|*", "a");
    test_match ("a\\|*", "a||");
    test_match ("\\(*\\)", ")");
    test_match ("\\(*\\)", "(()");
    test_match ("a\\|+", "a|");
    test_match ("a\\|+", "a||");
    test_match ("\\(+\\)", "()");
    test_match ("\\(+\\)", "(()");
    test_match ("a\\||b", "a|");
    test_match ("\\(?\\)", ")");
    test_match ("\\(?\\)", "()");

    test_match ("a+", "a");
    test_match ("a+", "aa");
    test_match ("a?", "");
    test_match ("a?", "a");

    /* Bracket expressions.  */
    test_match ("[(]", "(");
    test_match ("[+]", "+");
    test_match ("[?]", "?");
    test_match ("[{]", "{");
    test_match ("[|]", "|");
    /* Subexpressions.  */
    test_match ("(a+)*", "");
    test_match ("(a+)*", "aa");
    test_match ("(a?)*", "");
    test_match ("(a?)*", "aa");
    /* (No) back references.  */
    test_match ("(a)\\1", "a1");
    /* Invalid as intervals,
       but are valid patterns.  */
    MATCH_SELF ("{");
    test_match ("^{", "{");
    test_match ("a|{", "{");
    test_match ("({)", "{");
    MATCH_SELF ("a{");
    MATCH_SELF ("a{}");
    MATCH_SELF ("a{-1");
    MATCH_SELF ("a{-1}");
    MATCH_SELF ("a{0");
    MATCH_SELF ("a{0,");
    MATCH_SELF (concat ("a{", dup_max_plus_one));
    MATCH_SELF (concat (concat ("a{", dup_max_plus_one), ","));
    MATCH_SELF ("a{1,0");
    MATCH_SELF ("a{1,0}");
    MATCH_SELF ("a{0,1");
    test_match ("[a{0,1}]", "}");
    test_match ("a{1,3}{-1}", "aaa{-1}");
    test_match (concat ("a{1,3}{", dup_max_plus_one),
                concat ("aaa{", dup_max_plus_one));
    test_match ("a{1,3}{2,1}", "aaa{2,1}");
    test_match ("a{1,3}{1,2", "aaa{1,2");
    /* Valid consecutive repetitions.  */
    test_match ("a*+", "a");
    test_match ("a*?", "a");
    test_match ("a++", "a");
    test_match ("a+*", "a");
    test_match ("a+?", "a");
    test_match ("a??", "a");
    test_match ("a?*", "a");
    test_match ("a?+", "a");

    test_match ("a{2}?", "");
    test_match ("a{2}?", "aa");
    test_match ("a{2}+", "aa");
    test_match ("a{2}{2}", "aaaa");

    test_match ("a{1}?*", "");
    test_match ("a{1}?*", "aa");

    test_match ("(a?){0,3}b", "aaab");
    test_fastmap ("(a?){0,3}b", "ab", 0, 0);
    test_match ("(a+){0,3}b", "b");
    test_fastmap ("(a+){0,3}b", "ab", 0, 0);
    test_match ("(a+){0,3}b", "ab");
    test_fastmap ("(a+){0,3}b", "ab", 0, 0);
    test_match ("(a+){1,3}b", "aaab");
    test_match ("(a?){1,3}b", "aaab");

    test_match ("\\\\{1}", "\\");				/* Extended only.  */

    test_match ("(a?)?", "a");
    test_match ("(a?b)?c", "abc");
    test_match ("(a+)*b", "b");
    /* Alternatives.  */
    test_match ("a|b", "a");
    test_match ("a|b", "b");
    test_fastmap ("a|b", "ab", 0, 0);

    TEST_SEARCH ("a|b", "cb", 0, 2);
    TEST_SEARCH ("a|b", "cb", 0, 2);

    test_match ("(a|b|c)", "a");
    test_match ("(a|b|c)", "b");
    test_match ("(a|b|c)", "c");

    test_match ("(a|b|c)*", "abccba");

    test_match ("(a(b*))|c", "a");	/* xx do registers.  */
    test_match ("(a(b*))|c", "ab");
    test_match ("(a(b*))|c", "c");

    test_fastmap ("(a+?*|b)", "ab", 0, 0);
    test_match ("(a+?*|b)", "b");
    TEST_REGISTERS ("(a+?*|b)", "b", 0, 1, 0, 1, -1, -1);

    test_fastmap ("(a+?*|b)*", "ab", 0, 0);
    test_match ("(a+?*|b)*", "bb");
    TEST_REGISTERS ("(a+?*|b)*", "bb", 0, 2, 1, 2, -1, -1);

    test_fastmap ("(a*|b)*", "ab", 0, 0);
    test_match ("(a*|b)*", "bb");
    TEST_REGISTERS ("(a*|b)*", "bb", 0, 2, 1, 2, -1, -1);

    test_fastmap ("((a*)|b)*", "ab", 0, 0);
    test_match ("((a*)|b)*", "bb");
    TEST_REGISTERS ("((a*)|b)*", "bb", 0, 2, 1, 2, 1, 1);

    test_fastmap ("(a{0,}|b)*", "ab", 0, 0);
    test_match ("(a{0,}|b)*", "bb");
    TEST_REGISTERS ("(a{0,}|b)*", "bb", 0, 2, 1, 2, -1, -1);

    test_fastmap ("((a{0,})|b)*", "ab", 0, 0);
    test_match ("((a{0,})|b)*", "bb");
    TEST_REGISTERS ("((a{0,})|b)*", "bb", 0, 2, 1, 2, 1, 1);

    /* With c's  */
    test_fastmap ("(a+?*|b)c", "abc", 0, 0);
    test_match ("(a+?*|b)c", "bc");
    TEST_REGISTERS ("(a+?*|b)c", "bc", 0, 2, 0, 1, -1, -1);

    test_fastmap ("(a+?*|b)*c", "abc", 0, 0);
    test_match ("(a+?*|b)*c", "bbc");
    TEST_REGISTERS ("(a+?*|b)*c", "bbc", 0, 3, 1, 2, -1, -1);

    test_fastmap ("(a*|b)*c", "abc", 0, 0);
    test_match ("(a*|b)*c", "bbc");
    TEST_REGISTERS ("(a*|b)*c", "bbc", 0, 3, 1, 2, -1, -1);

    test_fastmap ("((a*)|b)*c", "abc", 0, 0);
    test_match ("((a*)|b)*c", "bbc");
    TEST_REGISTERS ("((a*)|b)*c", "bbc", 0, 3, 1, 2, 1, 1);

    test_fastmap ("(a{0,}|b)*c", "abc", 0, 0);
    test_match ("(a{0,}|b)*c", "bbc");
    TEST_REGISTERS ("(a{0,}|b)*c", "bbc", 0, 3, 1, 2, -1, -1);

    test_fastmap ("((a{0,})|b)*c", "abc", 0, 0);
    test_match ("((a{0,})|b)*c", "bbc");
    TEST_REGISTERS ("((a{0,})|b)*c", "bbc", 0, 3, 1, 2, 1, 1);


    test_fastmap ("((a{0,}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a{0,}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a{0,}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a{0,}\\b\\<)|b)*", "ab", 0, 0);
    test_match ("((a{0,}\\b\\<)|b)*", "b");
    TEST_REGISTERS ("((a{0,}\\b\\<)|b)*", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,1}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,1}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,1}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,2}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,2}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,2}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);


    test_fastmap ("((a+?*{0,4095}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,4095}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,4095}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,5119}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,5119}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,5119}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,6143}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,6143}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,6143}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,8191}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,8191}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,8191}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,16383}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,16383}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,16383}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);


    test_fastmap ("((a+?*{0,}\\b\\<)|b)", "ab", 0, 0);
    test_match ("((a+?*{0,}\\b\\<)|b)", "b");
    TEST_REGISTERS ("((a+?*{0,}\\b\\<)|b)", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,}\\b\\<)|b)*", "ab", 0, 0);
    test_match ("((a+?*{0,}\\b\\<)|b)*", "b");
    TEST_REGISTERS ("((a+?*{0,}\\b\\<)|b)*", "b",
                    0, 1, 0, 1, 0, 0);

    test_fastmap ("((a+?*{0,}\\b\\<)|b)*", "ab", 0, 0);
    test_match ("((a+?*{0,}\\b\\<)|b)*", "bb");
    TEST_REGISTERS ("((a+?*{0,}\\b\\<)|b)*", "bb",
                    0, 2, 1, 2, 0, 0);


    /* `*' after group.  */
    test_match ("(a*|b*)*c", "c");
    TEST_REGISTERS ("(a*|b*)*c", "c", 0, 1, 0, 0, -1, -1);

    test_match ("(a*|b*)*c", "ac");
    TEST_REGISTERS ("(a*|b*)*c", "ac", 0, 2, 0, 1, -1, -1);

    test_match ("(a*|b*)*c", "aac");
    TEST_REGISTERS ("(a*|b*)*c", "aac", 0, 3, 0, 2, -1, -1);

    test_match ("(a*|b*)*c", "bbc");
    TEST_REGISTERS ("(a*|b*)*c", "bbc", 0, 3, 0, 2, -1, -1);

    test_match ("(a*|b*)*c", "abc");
    TEST_REGISTERS ("(a*|b*)*c", "abc", 0, 3, 1, 2, -1, -1);

    /* No `*' after group.  */
    test_match ("(a*|b*)c", "c");
    TEST_REGISTERS ("(a*|b*)c", "c", 0, 1, 0, 0, -1, -1);

    test_match ("(a*|b*)c", "ac");
    TEST_REGISTERS ("(a*|b*)c", "ac", 0, 2, 0, 1, -1, -1);

    test_match ("(a*|b*)c", "bc");
    TEST_REGISTERS ("(a*|b*)c", "bc", 0, 2, 0, 1, -1, -1);

    test_match ("(a*|b*)c", "aac");
    TEST_REGISTERS ("(a*|b*)c", "aac", 0, 3, 0, 2, -1, -1);

    /* Same as above, but with no `*'s in alternatives.

    test_match ("(a|b)*c", "c");		/* `*' after group.  */
    TEST_REGISTERS ("(a|b)*c", "c", 0, 1, -1, -1, -1, -1);

    test_match ("(a|b)*c", "ac");
    TEST_REGISTERS ("(a|b)*c", "ac", 0, 2, 0, 1, -1, -1);

    test_match ("(a|b)*c", "bc");
    TEST_REGISTERS ("(a|b)*c", "bc", 0, 2, 0, 1, -1, -1);

    test_match ("(a|b)*c", "abc");
    TEST_REGISTERS ("(a|b)*c", "abc", 0, 3, 1, 2, -1, -1);


    test_match ("(a*|b*)c", "bbc");
    TEST_REGISTERS ("(a*|b*)c", "bbc", 0, 3, 0, 2, -1, -1);

    /* Complicated second alternative.  */

    test_match ("(a*|(b*)*)*c", "bc");
    TEST_REGISTERS ("(a*|(b*)*)*c", "bc", 0, 2, 0, 1, 0, 1);

    test_match ("(a*|(b*|c*)*)*d", "bd");
    TEST_REGISTERS ("(a*|(b*|c*)*)*d", "bd", 0, 2, 0, 1, 0, 1);

    test_match ("(a*|(b*|c*)*)*d", "bbd");
    TEST_REGISTERS ("(a*|(b*|c*)*)*d", "bbd", 0, 3, 0, 2, 0, 2);

    test_match ("(a*|(b*|c*)*)*d", "cd");
    TEST_REGISTERS ("(a*|(b*|c*)*)*d", "cd", 0, 2, 0, 1, 0, 1);

    test_match ("(a*|(b*|c*)*)*d", "ccd");
    TEST_REGISTERS ("(a*|(b*|c*)*)*d", "ccd", 0, 3, 0, 2, 0, 2);

    test_match ("(a*|b*|c*)*d", "aad");
    TEST_REGISTERS ("(a*|b*|c*)*d", "aad", 0, 3, 0, 2, 0, 2);

    test_match ("(a*|b*|c*)*d", "bbd");
    TEST_REGISTERS ("(a*|b*|c*)*d", "bbd", 0, 3, 0, 2, 0, 2);

    test_match ("(a*|b*|c*)*d", "ccd");
    TEST_REGISTERS ("(a*|b*|c*)*d", "ccd", 0, 3, 0, 2, 0, 2);

    /* Valid anchoring.  */
    valid_pattern ("a^");
    valid_pattern ("a^b");
    valid_pattern ("$a");
    valid_pattern ("a$b");
    valid_pattern ("foo^bar");
    valid_pattern ("foo$bar");
    valid_pattern ("(^)");
    valid_pattern ("($)");
    valid_pattern ("(^$)");

    /* These are the same (but valid) as those (invalid) in other_test.c.  */
    valid_pattern
    ("(((((((((((((((((((((((((((((((((a^)))))))))))))))))))))))))))))))))");
    valid_pattern
    ("((((((((((((((((((((((((((((((((($a)))))))))))))))))))))))))))))))))");
    valid_pattern ("\\(^a\\)");
    valid_pattern ("a\\|^b");
    valid_pattern ("\\w^a");
    valid_pattern ("\\W^a");
    valid_pattern ("(a^)");
    valid_pattern ("($a)");
    valid_pattern ("a(^b)");
    valid_pattern ("a$(b)");
    valid_pattern ("(a)^b");
    valid_pattern ("(a)$b");
    valid_pattern ("(a)(^b)");
    valid_pattern ("(a$)(b)");
    valid_pattern ("(a|b)^c");
    valid_pattern ("(a|b)$c");
    valid_pattern ("(a$|b)c");
    valid_pattern ("(a|b$)c");
    valid_pattern ("a(b|^c)");
    valid_pattern ("a(^b|c)");
    valid_pattern ("a$(b|c)");
    valid_pattern ("(a)(^b|c)");
    valid_pattern ("(a)(b|^c)");
    valid_pattern ("(b$|c)(a)");
    valid_pattern ("(b|c$)(a)");
    valid_pattern ("(a(^b|c))");
    valid_pattern ("(a(b|^c))");
    valid_pattern ("((b$|c)a)");
    valid_pattern ("((b|c$)a)");
    valid_pattern ("((^a|^b)^c)");
    valid_pattern ("(c$(a$|b$))");
    valid_pattern ("((^a|^b)^c)");
    valid_pattern ("((a$|b$)c)");
    valid_pattern ("(c$(a$|b$))");
    valid_pattern ("((^a|^b)|^c)^d");
    valid_pattern ("((a$|b$)|c$)d$");
    valid_pattern ("d$(c$|(a$|b$))");
    valid_pattern ("((^a|^b)|^c)(^d)");
    valid_pattern ("((a$|b$)|c$)(d$)");
    valid_pattern ("(d$)((a$|b$)|c$)");
    valid_pattern ("((^a|^b)|^c)((^d))");
    valid_pattern ("((a$|b$)|c$)((d$))");
    valid_pattern ("((d$))((a$|b$)|c$)");
    valid_pattern ("(((^a|^b))c|^d)^e");
    valid_pattern ("(((a$|b$))c|d$)$e$");
    valid_pattern ("e$(d$|c((a$|b$)))");
    valid_pattern ("(^a)((^b))");
    valid_pattern ("(a$)((b$))");
    valid_pattern ("((^a))(^b)");
    valid_pattern ("((a$))(b$)");
    valid_pattern ("((^a))((^b))");
    valid_pattern ("((a$))((b$))");
    valid_pattern ("((^a)^b)");
    valid_pattern ("((a$)b$)");
    valid_pattern ("(b$(a$))");
    valid_pattern ("(((^a)b)^c)");
    valid_pattern ("(((a$)b)c$)");
    valid_pattern ("(c$(b(a$)))");
    valid_pattern ("(((^a)b)c)^d");
    valid_pattern ("(((a$)b)c)d$");
    valid_pattern ("d$(c(b(a$)))");
    valid_pattern (".^a");
    valid_pattern ("a$.");
    valid_pattern ("[a]^b");
    valid_pattern ("b$[a]");
    valid_pattern ("\\(a$\\)");
    valid_pattern ("a$\\|b");
    valid_pattern ("(^a|^b)^c");
    valid_pattern ("c$(a$|b$)");
    valid_pattern ("(^a|^b)^|^c");
    valid_pattern ("(a$|b$)$|$c$");
    valid_pattern ("(a$|$b$)$|c$");
    valid_pattern ("($a$|b$)$|c$");
    valid_pattern ("$(a$|b$)$|c$");
    valid_pattern ("^c|d(^a|^b)");
    valid_pattern ("(^a|^b)|d^c");
    valid_pattern ("c$|(a$|b$)d");
    valid_pattern ("c$d|(a$|b$)");
    valid_pattern ("c(^a|^b)|^d");
    valid_pattern ("(a$|b$)c|d$");
    valid_pattern ("c(((^a|^b))|^d)e");
    valid_pattern ("(c((^a|^b))|^d)e");
    valid_pattern ("((c(^a|^b))|^d)e");
    valid_pattern ("(((^a|^b))|c^d)e");
    valid_pattern ("(((^a|^b))|^d)^e");
    valid_pattern ("(c$((a|b))|d)e$");
    valid_pattern ("(c((a$|b$))|d)e$");
    valid_pattern ("(c((a|b)$)|d)e$");
    valid_pattern ("(c((a|b))|d$)e$");
    valid_pattern ("^d(^c|e((a|b)))");
    valid_pattern ("^d(c|^e((a|b)))");
    valid_pattern ("^d(c|e(^(a|b)))");
    valid_pattern ("^d(c|e((^a|b)))");
    valid_pattern ("^d(c|e((a|^b)))");
    valid_pattern ("^d(c|e((a|b^)))");
    valid_pattern ("^d(c|e((a|b)^))");
    valid_pattern ("^d(c|e((a|b))^)");
    valid_pattern ("^d(c|e((a|b)))^");
    valid_pattern ("d$(c$|e((a$|b$)))");
    valid_pattern ("d(c$|e$((a$|b$)))");
    valid_pattern ("(((^a|^b))^c)|^de");
    valid_pattern ("(((^a|^b))c)|^d^e");
    valid_pattern ("(((a$|b))c$)|de$");
    valid_pattern ("(((a|b$))c$)|de$");
    valid_pattern ("(((a|b))c$)|d$e$");
    valid_pattern ("^d^e|^(c((a|b)))");
    valid_pattern ("^de|^(c^((a|b)))");
    valid_pattern ("^de|^(c(^(a|b)))");
    valid_pattern ("^de|^(c((^a|b)))");
    valid_pattern ("^de|^(c((a|^b)))");
    valid_pattern ("^de|(^c(^(a|b)))");
    valid_pattern ("^de|(^c((^a|b)))");
    valid_pattern ("^de|(^c((a|^b)))");
    valid_pattern ("de$|(c($(a|b)$))");
    valid_pattern ("de$|(c$((a|b)$))");
    valid_pattern ("de$|($c((a|b)$))");
    valid_pattern ("de$|$(c((a|b)$))");
    valid_pattern ("de$|(c($(a|b))$)");
    valid_pattern ("de$|(c$((a|b))$)");
    valid_pattern ("de$|$(c((a|b))$)");
    valid_pattern ("de$|(c($(a|b)))$");
    valid_pattern ("de$|(c$((a|b)))$");
    valid_pattern ("de$|($c((a|b)))$");
    valid_pattern ("de$|$(c((a|b)))$");
    valid_pattern ("^a(^b|c)|^d");
    valid_pattern ("^a(b|^c)|^d");
    valid_pattern ("^a(b|c^)|^d");
    valid_pattern ("^a(b|c)^|^d");
    valid_pattern ("a$(b$|c$)|d$");
    valid_pattern ("^d|^a(^b|c)");
    valid_pattern ("^d|^a(b|^c)");
    valid_pattern ("d$|a$(b$|c$)");
    valid_pattern ("^d|^(b|c)^a");
    valid_pattern ("d$|(b|c$)a$");
    valid_pattern ("d$|(b$|c)a$");
    valid_pattern ("^(a)^(b|c)|^d");
    valid_pattern ("^(a)(^b|c)|^d");
    valid_pattern ("^(a)(b|^c)|^d");
    valid_pattern ("(a)$(b|c)$|d$");
    valid_pattern ("(a$)(b|c)$|d$");
    valid_pattern ("(^a)(^b|c)|^d");
    valid_pattern ("(^a)(b|^c)|^d");
    valid_pattern ("(a)$(b$|c$)|d$");
    valid_pattern ("(a$)(b$|c$)|d$");
    valid_pattern ("^d|^(b|c)^(a)");
    valid_pattern ("^d|^(b|c)(^a)");
    valid_pattern ("d$|(b|c$)(a)$");
    valid_pattern ("d$|(b$|c)(a)$");
    valid_pattern ("^d|(^b|^c)^(a)");
    valid_pattern ("^d|(^b|^c)(^a)");
    valid_pattern ("d$|(b|c)$(a$)");
    valid_pattern ("d$|(b|c$)(a$)");
    valid_pattern ("d$|(b$|c)(a$)");
    valid_pattern ("^d|^(a)^(b|c)");
    valid_pattern ("^d|^(a)(^b|c)");
    valid_pattern ("^d|^(a)(b|^c)");
    valid_pattern ("^d|(^a)^(b|c)");
    valid_pattern ("^d|(^a)(^b|c)");
    valid_pattern ("^d|(^a)(b|^c)");
    valid_pattern ("d$|(a)$(b$|c$)");
    valid_pattern ("d$|(a$)(b$|c$)");
    valid_pattern ("((e^a|^b)|^c)|^d");
    valid_pattern ("((^a|e^b)|^c)|^d");
    valid_pattern ("((^a|^b)|e^c)|^d");
    valid_pattern ("((^a|^b)|^c)|e^d");
    valid_pattern ("d$e|(c$|(a$|b$))");
    valid_pattern ("d$|(c$e|(a$|b$))");
    valid_pattern ("d$|(c$|(a$e|b$))");
    valid_pattern ("d$|(c$|(a$|b$e))");
    valid_pattern ("d$|(c$|(a$|b$)e)");
    valid_pattern ("d$|(c$|(a$|b$))e");
    valid_pattern ("(a|b)^|c");
    valid_pattern ("(a|b)|c^");
    valid_pattern ("$(a|b)|c");
    valid_pattern ("(a|b)|$c");
    valid_pattern ("(a^|^b)|^c");
    valid_pattern ("(^a|b^)|^c");
    valid_pattern ("(^a|^b)|c^");
    valid_pattern ("($a|b$)|c$");
    valid_pattern ("(a$|$b)|c$");
    valid_pattern ("(a$|b$)|$c");
    valid_pattern ("c^|(^a|^b)");
    valid_pattern ("^c|(a^|^b)");
    valid_pattern ("^c|(^a|b^)");
    valid_pattern ("$c|(a$|b$)");
    valid_pattern ("c$|($a|b$)");
    valid_pattern ("c$|(a$|$b)");
    valid_pattern ("c^|^(a|b)");
    valid_pattern ("^c|(a|b)^");
    valid_pattern ("$c|(a|b)$");
    valid_pattern ("c$|$(a|b)");
    valid_pattern ("(a^|^b)c|^d");
    valid_pattern ("(^a|b^)c|^d");
    valid_pattern ("(^a|^b)c|d^");
    valid_pattern ("(^a|^b)^c|^d");
    valid_pattern ("(a|b)c$|$d");
    valid_pattern ("(a|b)$c$|d$");
    valid_pattern ("(a|b)$c$|d$");
    valid_pattern ("(a|b$)c$|d$");
    valid_pattern ("(a$|b)c$|d$");
    valid_pattern ("($a|b)c$|d$");
    valid_pattern ("$(a|b)c$|d$");
    valid_pattern ("^d|^c^(a|b)");
    valid_pattern ("^d|^c(^a|b)");
    valid_pattern ("^d|^c(a|^b)");
    valid_pattern ("^d|^c(a|b^)");
    valid_pattern ("^d|^c(a|b)^");
    valid_pattern ("$d|c(a$|b$)");
    valid_pattern ("d$|c($a$|b$)");
    valid_pattern ("d$|c$(a$|b$)");
    valid_pattern ("d$|$c(a$|b$)");

    valid_pattern ("(((a^|^b))c|^d)e");
    valid_pattern ("(((^a|b^))c|^d)e");
    valid_pattern ("(((^a|^b))^c|^d)e");
    valid_pattern ("((^(a|b))c|d^)e");
    valid_pattern ("(^((a|b))c|^d)^e");
    valid_pattern ("(^((a|b)^)c|^d)e");
    valid_pattern ("(^((a^|b))c|^d)e");
    valid_pattern ("(^((a|b^))c|^d)e");
    valid_pattern ("(^((a|b)^)c|^d)e");
    valid_pattern ("(^((a|b))^c|^d)e");
    valid_pattern ("(^((a|b))c^|^d)e");
    valid_pattern ("(^((a|b))c|^d^)e");
    valid_pattern ("(^((a|b))c|^d)^e");
    valid_pattern ("(((a|b))c|d)$e$");
    valid_pattern ("(((a|b))c|d$)e$");
    valid_pattern ("(((a|b))c|$d)e$");
    valid_pattern ("(((a|b))c$|d)e$");
    valid_pattern ("(((a|b))$c|d)e$");
    valid_pattern ("(((a|b)$)c|d)e$");
    valid_pattern ("(((a|b$))c|d)e$");
    valid_pattern ("(((a$|b))c|d)e$");
    valid_pattern ("((($a|b))c|d)e$");
    valid_pattern ("(($(a|b))c|d)e$");
    valid_pattern ("($((a|b))c|d)e$");
    valid_pattern ("$(((a|b))c|d)e$");
    valid_pattern ("(^((a|b)^)c|^d)e");
    valid_pattern ("(^((a|b))^c|^d)e");
    valid_pattern ("(^((a|b))c|^d^)e");
    valid_pattern ("(^((a|b))c|^d)^e");

    valid_pattern ("^e(^d|c((a|b)))");
    valid_pattern ("^e(d|^c((a|b)))");
    valid_pattern ("^e(d|c^((a|b)))");
    valid_pattern ("^e(d|c(^(a|b)))");
    valid_pattern ("^e(d|c((^a|b)))");
    valid_pattern ("^e(d|c((a|^b)))");
    valid_pattern ("^e(d|c((a|b^)))");
    valid_pattern ("^e(d|c((a|b)^))");
    valid_pattern ("^e(d|c((a|b))^)");
    valid_pattern ("^e(d|c((a|b)))^");
    valid_pattern ("e$(d$|c((a$|b$)))");
    valid_pattern ("e(d$|c$((a$|b$)))");
    valid_pattern ("e(d$|c($(a$|b$)))");
    valid_pattern ("e(d$|c(($a$|b$)))");
    valid_pattern ("e$(d$|c((a|b)$))");
    valid_pattern ("e($d$|c((a|b)$))");
    valid_pattern ("e(d$|$c((a|b)$))");
    valid_pattern ("e(d$|c$((a|b)$))");
    valid_pattern ("e(d$|c($(a|b)$))");
    valid_pattern ("e(d$|c(($a|b)$))");
    valid_pattern ("e(d$|c((a|$b)$))");
    valid_pattern ("e(d$|c((a$|$b$)))");

    valid_pattern ("e$(d$|c((a|b))$)");
    valid_pattern ("e($d$|c((a|b))$)");
    valid_pattern ("e(d$|$c((a|b))$)");
    valid_pattern ("e(d$|c$((a|b))$)");
    valid_pattern ("e(d$|c($(a|b))$)");
    valid_pattern ("e(d$|c(($a|b))$)");
    valid_pattern ("e(d$|c((a|$b))$)");
    valid_pattern ("e$(d$|c((a|b)))$");
    valid_pattern ("e($d$|c((a|b)))$");
    valid_pattern ("e(d$|$c((a|b)))$");
    valid_pattern ("e(d$|c$((a|b)))$");
    valid_pattern ("e(d$|c($(a|b)))$");
    valid_pattern ("e(d$|c(($a|b)))$");
    valid_pattern ("e(d$|c((a|$b)))$");
    valid_pattern ("(((^a|^b)^)c)|^de");
    valid_pattern ("(((^a|^b))^c)|^de");
    valid_pattern ("(((^a|^b))c)^|^de");
    valid_pattern ("$(((a|b))c$)|de$");
    valid_pattern ("($((a|b))c$)|de$");
    valid_pattern ("(($(a|b))c$)|de$");
    valid_pattern ("((($a|b))c$)|de$");
    valid_pattern ("(((a|$b))c$)|de$");
    valid_pattern ("(((a|b)$)c$)|de$");
    valid_pattern ("(((a|b))$c$)|de$");
    valid_pattern ("$(((a|b))c)$|de$");
    valid_pattern ("($((a|b))c)$|de$");
    valid_pattern ("(($(a|b))c)$|de$");
    valid_pattern ("((($a|b))c)$|de$");
    valid_pattern ("(((a|$b))c)$|de$");
    valid_pattern ("(((a|b)$)c)$|de$");
    valid_pattern ("(((a|b))$c)$|de$");
    valid_pattern ("^ed|^(c((a|b)))^");
    valid_pattern ("^ed|^(c((a|b))^)");
    valid_pattern ("^ed|^(c((a|b)^))");
    valid_pattern ("^ed|^(c((a|b^)))");
    valid_pattern ("^ed|^(c((a^|b)))");
    valid_pattern ("^ed|^(c((^a|b)))");
    valid_pattern ("^ed|^(c(^(a|b)))");
    valid_pattern ("^ed|^(c^((a|b)))");
    valid_pattern ("^ed|(^c((a|b)))^");
    valid_pattern ("^ed|(^c((a|b))^)");
    valid_pattern ("^ed|(^c((a|b)^))");
    valid_pattern ("^ed|(^c((a|b^)))");
    valid_pattern ("^ed|(^c((a|^b)))");
    valid_pattern ("^ed|(^c((a^|b)))");
    valid_pattern ("^ed|(^c((^a|b)))");
    valid_pattern ("^ed|(^c(^(a|b)))");
    valid_pattern ("^ed|(^c(^(a|b)))");
    valid_pattern ("^ed|(^c^((a|b)))");
    valid_pattern ("ed$|$(c((a|b)))$");
    valid_pattern ("ed$|($c((a|b)))$");
    valid_pattern ("ed$|(c$((a|b)))$");
    valid_pattern ("ed$|(c($(a|b)))$");
    valid_pattern ("ed$|(c(($a|b)))$");
    valid_pattern ("ed$|(c((a|$b)))$");
    valid_pattern ("ed$|$(c((a|b))$)");
    valid_pattern ("ed$|($c((a|b))$)");
    valid_pattern ("ed$|(c$((a|b))$)");
    valid_pattern ("ed$|(c($(a|b))$)");
    valid_pattern ("ed$|(c(($a|b))$)");
    valid_pattern ("ed$|(c((a|$b))$)");
    valid_pattern ("ed$|$(c((a|b)$))");
    valid_pattern ("ed$|($c((a|b)$))");
    valid_pattern ("ed$|(c$((a|b)$))");
    valid_pattern ("ed$|(c($(a|b)$))");
    valid_pattern ("ed$|(c(($a|b)$))");
    valid_pattern ("ed$|(c((a|$b)$))");
    valid_pattern ("ed$|$(c((a|b)$))");
    valid_pattern ("ed$|($c((a|b)$))");
    valid_pattern ("ed$|(c$((a|b)$))");
    valid_pattern ("ed$|(c($(a|b)$))");
    valid_pattern ("ed$|(c(($a|b)$))");
    valid_pattern ("ed$|(c((a|$b)$))");
    valid_pattern ("ed$|$(c((a|b)$))");
    valid_pattern ("ed$|($c((a|b)$))");
    valid_pattern ("ed$|(c$((a|b)$))");
    valid_pattern ("ed$|(c($(a|b)$))");
    valid_pattern ("ed$|(c(($a|b)$))");
    valid_pattern ("ed$|(c((a|$b)$))");
    valid_pattern ("ed$|$(c((a|b)$))");
    valid_pattern ("ed$|($c((a|b)$))");
    valid_pattern ("ed$|(c$((a|b)$))");
    valid_pattern ("ed$|(c($(a|b)$))");
    valid_pattern ("ed$|(c(($a|b)$))");
    valid_pattern ("ed$|(c((a|$b)$))");
    valid_pattern ("ed$|$(c((a|b)$))");
    valid_pattern ("ed$|($c((a|b)$))");
    valid_pattern ("ed$|(c$((a|b)$))");
    valid_pattern ("ed$|(c($(a|b)$))");
    valid_pattern ("ed$|(c(($a|b)$))");
    valid_pattern ("ed$|(c((a|$b)$))");
    valid_pattern ("ed$|$(c((a$|b$)))");
    valid_pattern ("ed$|($c((a$|b$)))");
    valid_pattern ("ed$|(c$((a$|b$)))");
    valid_pattern ("ed$|(c($(a$|b$)))");
    valid_pattern ("ed$|(c(($a$|b$)))");
    valid_pattern ("ed$|(c((a$|$b$)))");
    valid_pattern ("^a(b|c)^|^d");
    valid_pattern ("^a(b|c^)|^d");
    valid_pattern ("^a(b|^c)|^d");
    valid_pattern ("^a(b^|c)|^d");
    valid_pattern ("^a(^b|c)|^d");
    valid_pattern ("^a^(b|c)|^d");
    valid_pattern ("$a(b$|c$)|d$");
    valid_pattern ("a$(b$|c$)|d$");
    valid_pattern ("a($b$|c$)|d$");
    valid_pattern ("a(b$|$c$)|d$");
    valid_pattern ("a(b$|c$)|$d$");
    valid_pattern ("^(a^)(b|c)|^d");
    valid_pattern ("^(a)^(b|c)|^d");
    valid_pattern ("^(a)(^b|c)|^d");
    valid_pattern ("^(a)(b^|c)|^d");
    valid_pattern ("^(a)(b|^c)|^d");
    valid_pattern ("^(a)(b|c^)|^d");
    valid_pattern ("^(a)(b|c)^|^d");
    valid_pattern ("(^a^)(b|c)|^d");
    valid_pattern ("(^a)^(b|c)|^d");
    valid_pattern ("(^a)(^b|c)|^d");
    valid_pattern ("(^a)(b^|c)|^d");
    valid_pattern ("(^a)(b|^c)|^d");
    valid_pattern ("(^a)(b|c^)|^d");
    valid_pattern ("(^a)(b|c)^|^d");

    valid_pattern ("(a)(b$|c$)d$");
    valid_pattern ("(a)(b|$c)$|d$");
    valid_pattern ("(a)($b|c)$|d$");
    valid_pattern ("(a)$(b|c)$|d$");
    valid_pattern ("(a$)(b|c)$|d$");
    valid_pattern ("($a)(b|c)$|d$");
    valid_pattern ("$(a)(b|c)$|d$");
    valid_pattern ("(b|c)($a)$|d$");
    valid_pattern ("(b|c)$(a)$|d$");
    valid_pattern ("(b|c$)(a)$|d$");
    valid_pattern ("(b|$c)(a)$|d$");
    valid_pattern ("(b$|c)(a)$|d$");
    valid_pattern ("($b|c)(a)$|d$");
    valid_pattern ("$(b|c)(a)$|d$");
    valid_pattern ("(b|c)($a$)|d$");
    valid_pattern ("(b|c)$(a$)|d$");
    valid_pattern ("(b|c$)(a$)|d$");
    valid_pattern ("(b|$c)(a$)|d$");
    valid_pattern ("(b$|c)(a$)|d$");
    valid_pattern ("($b|c)(a$)|d$");
    valid_pattern ("$(b|c)(a$)|d$");
    valid_pattern ("(a)$(b$|c$)|d$");
    valid_pattern ("(a$)(b$|c$)|d$");
    valid_pattern ("($a)(b$|c$)|d$");
    valid_pattern ("$(a)(b$|c$)|d$");
    valid_pattern ("^d|^(b^|c)(a)");
    valid_pattern ("^d|^(b|c^)(a)");
    valid_pattern ("^d|^(b|c)^(a)");
    valid_pattern ("^d|^(b|c)(^a)");
    valid_pattern ("^d|^(b|c)(a^)");
    valid_pattern ("^d|^(b|c)(a)^");
    valid_pattern ("^d|(^b|^c^)(a)");
    valid_pattern ("^d|(^b|^c)^(a)");
    valid_pattern ("^d|(^b|^c)(^a)");
    valid_pattern ("^d|(^b|^c)(a^)");
    valid_pattern ("^d|(^b|^c)(a)^");
    valid_pattern ("d$|(b|c)($a$)");
    valid_pattern ("d$|(b|c)$(a$)");
    valid_pattern ("d$|(b|c$)(a$)");
    valid_pattern ("d$|(b$|c)(a$)");
    valid_pattern ("d$|($b|c)(a$)");
    valid_pattern ("d$|$(b|c)(a$)");
    valid_pattern ("d$|(b|c)($a)$");
    valid_pattern ("d$|(b|c)$(a)$");
    valid_pattern ("d$|(b|c$)(a)$");
    valid_pattern ("d$|(b$|c)(a)$");
    valid_pattern ("d$|($b|c)(a)$");
    valid_pattern ("d$|$(b|c)(a)$");
    valid_pattern ("^d|^(a^)(b|c)");
    valid_pattern ("^d|^(a)^(b|c)");
    valid_pattern ("^d|^(a)(^b|c)");
    valid_pattern ("^d|^(a)(b^|c)");
    valid_pattern ("^d|^(a)(b|^c)");
    valid_pattern ("^d|^(a)(b|c^)");
    valid_pattern ("^d|^(a)(b|c)^");
    valid_pattern ("^d|(^a^)(b|c)");
    valid_pattern ("^d|(^a)^(b|c)");
    valid_pattern ("^d|(^a)(^b|c)");
    valid_pattern ("^d|(^a)(b^|c)");
    valid_pattern ("^d|(^a)(b|^c)");
    valid_pattern ("^d|(^a)(b|c^)");
    valid_pattern ("^d|(^a)(b|c)^");
    valid_pattern ("d$|(a)$(b$|c$)");
    valid_pattern ("d$|(a$)(b$|c$)");
    valid_pattern ("d$|($a)(b$|c$)");
    valid_pattern ("d$|$(a)(b$|c$)");
    valid_pattern ("d$|(a)(b|$c)$");
    valid_pattern ("d$|(a)($b|c)$");
    valid_pattern ("d$|(a)$(b|c)$");
    valid_pattern ("d$|(a$)(b|c)$");
    valid_pattern ("d$|($a)(b|c)$");
    valid_pattern ("d$|$(a)(b|c)$");
    valid_pattern ("((^a|^b)|^c)|^d^");
    valid_pattern ("((^a|^b)|^c)^|^d");
    valid_pattern ("((^a|^b)|^c^)|^d");
    valid_pattern ("((^a|^b)^|^c)|^d");
    valid_pattern ("((^a|^b^)|^c)|^d");
    valid_pattern ("((^a^|^b)|^c)|^d");
    valid_pattern ("((a|b)|c)|$d$");
    valid_pattern ("((a|b)|$c)|d$");
    valid_pattern ("((a|$b)|c)|d$");
    valid_pattern ("(($a|b)|c)|d$");
    valid_pattern ("($(a|b)|c)|d$");
    valid_pattern ("$((a|b)|c)|d$");
    valid_pattern ("^d^|(c|(a|b))");
    valid_pattern ("^d|(c^|(a|b))");
    valid_pattern ("^d|(c|(a^|b))");
    valid_pattern ("^d|(c|(a|b^))");
    valid_pattern ("^d|(c|(a|b)^)");
    valid_pattern ("^d|(c|(a|b))^");
    valid_pattern ("d$|(c$|(a$|$b$))");
    valid_pattern ("d$|(c$|($a$|b$))");
    valid_pattern ("d$|($c$|(a$|b$))");
    valid_pattern ("d$|$(c$|(a$|b$))");
    valid_pattern ("$d$|(c$|(a$|b$))");
    valid_pattern ("d$|(c$|(a|$b)$)");
    valid_pattern ("d$|(c$|($a|b)$)");
    valid_pattern ("d$|($c$|(a|b)$)");
    valid_pattern ("d$|$(c$|(a|b)$)");
    valid_pattern ("$d$|(c$|(a|b)$)");
    valid_pattern ("d$|(c$|(a|$b))$");
    valid_pattern ("d$|(c$|($a|b))$");
    valid_pattern ("d$|($c$|(a|b))$");
    valid_pattern ("d$|$(c$|(a|b))$");
    valid_pattern ("$d$|(c$|(a|b))$");
    valid_pattern ("^c^|(^a|^b)");
    valid_pattern ("^c|(^a^|^b)");
    valid_pattern ("^c|(^a|^b^)");
    valid_pattern ("^c|(^a|^b)^");
    valid_pattern ("c$|(a$|$b$)");
    valid_pattern ("c$|($a$|b$)");
    valid_pattern ("c$|$(a$|b$)");
    valid_pattern ("$c$|(a$|b$)");
    valid_pattern ("^d^(c|e((a|b)))");
    valid_pattern ("^d(^c|e((a|b)))");
    valid_pattern ("^d(c^|e((a|b)))");
    valid_pattern ("^d(c|^e((a|b)))");
    valid_pattern ("^d(c|e^((a|b)))");
    valid_pattern ("^d(c|e(^(a|b)))");
    valid_pattern ("^d(c|e((^a|b)))");
    valid_pattern ("^d(c|e((a|^b)))");
    valid_pattern ("^d(c|e((a|b^)))");
    valid_pattern ("^d(c|e((a|b)^))");
    valid_pattern ("^d(c|e((a|b))^)");
    valid_pattern ("^d(c|e((a|b)))^");
    valid_pattern ("d(c$|e($(a$|b$)))");
    valid_pattern ("d(c$|e$((a$|b$)))");
    valid_pattern ("d(c$|$e((a$|b$)))");
    valid_pattern ("d($c$|e((a$|b$)))");
    valid_pattern ("d$(c$|e((a$|b$)))");
    valid_pattern ("$d(c$|e((a$|b$)))");
    valid_pattern ("^d|^a^(b|c)");
    valid_pattern ("^d|^a(^b|c)");
    valid_pattern ("^d|^a(b^|c)");
    valid_pattern ("^d|^a(b|^c)");
    valid_pattern ("^d|^a(b|c^)");
    valid_pattern ("^d|^a(b|c)^");
    valid_pattern ("d$|a($b$|c$)");
    valid_pattern ("d$|a$(b$|c$)");
    valid_pattern ("d$|$a(b$|c$)");
    valid_pattern ("$d$|a(b$|c$)");
    valid_pattern ("^d|^(b^|c)a");
    valid_pattern ("^d|^(b|c^)a");
    valid_pattern ("^d|^(b|c)^a");
    valid_pattern ("^d|^(b|c)a^");
    valid_pattern ("d$|(b|c)$a$");
    valid_pattern ("d$|(b|c$)a$");
    valid_pattern ("d$|(b|$c)a$");
    valid_pattern ("d$|(b$|c)a$");
    valid_pattern ("d$|($b|c)a$");
    valid_pattern ("d$|$(b|c)a$");
    valid_pattern ("$d$|(b|c)a$");

    /* xx Do these use all the valid_nonposix_pattern ones in other_test.c?  */

    TEST_SEARCH ("(^a|^b)c", "ac", 0, 2);
    TEST_SEARCH ("(^a|^b)c", "bc", 0, 2);
    TEST_SEARCH ("c(a$|b$)", "ca", 0, 2);
    TEST_SEARCH ("c(a$|b$)", "cb", 0, 2);
    TEST_SEARCH ("^(a|b)|^c", "ad", 0, 2);
    TEST_SEARCH ("^(a|b)|^c", "bd", 0, 2);
    TEST_SEARCH ("(a|b)$|c$", "da", 0, 2);
    TEST_SEARCH ("(a|b)$|c$", "db", 0, 2);
    TEST_SEARCH ("(a|b)$|c$", "dc", 0, 2);
    TEST_SEARCH ("(^a|^b)|^c", "ad", 0, 2);
    TEST_SEARCH ("(^a|^b)|^c", "bd", 0, 2);
    TEST_SEARCH ("(^a|^b)|^c", "cd", 0, 2);
    TEST_SEARCH ("(a$|b$)|c$", "da", 0, 2);
    TEST_SEARCH ("(a$|b$)|c$", "db", 0, 2);
    TEST_SEARCH ("(a$|b$)|c$", "dc", 0, 2);
    TEST_SEARCH ("^c|(^a|^b)", "ad", 0, 2);
    TEST_SEARCH ("^c|(^a|^b)", "bd", 0, 2);
    TEST_SEARCH ("^c|(^a|^b)", "cd", 0, 2);
    TEST_SEARCH ("c$|(a$|b$)", "da", 0, 2);
    TEST_SEARCH ("c$|(a$|b$)", "db", 0, 2);
    TEST_SEARCH ("c$|(a$|b$)", "dc", 0, 2);
    TEST_SEARCH ("^c|^(a|b)", "ad", 0, 2);
    TEST_SEARCH ("^c|^(a|b)", "bd", 0, 2);
    TEST_SEARCH ("^c|^(a|b)", "cd", 0, 2);
    TEST_SEARCH ("c$|(a|b)$", "da", 0, 2);
    TEST_SEARCH ("c$|(a|b)$", "db", 0, 2);
    TEST_SEARCH ("c$|(a|b)$", "dc", 0, 2);
    TEST_SEARCH ("(^a|^b)c|^d", "ace", 0, 3);
    TEST_SEARCH ("(^a|^b)c|^d", "bce", 0, 3);
    TEST_SEARCH ("(^a|^b)c|^d", "de", 0, 2);
    TEST_SEARCH ("(a|b)c$|d$", "eac", 0, 3);
    TEST_SEARCH ("(a|b)c$|d$", "ebc", 0, 3);
    TEST_SEARCH ("(a|b)c$|d$", "ed", 0, 3);
    TEST_SEARCH ("^d|^c(a|b)", "cae", 0, 3);
    TEST_SEARCH ("^d|^c(a|b)", "cbe", 0, 3);
    TEST_SEARCH ("^d|^c(a|b)", "de", 0, 3);
    TEST_SEARCH ("d$|c(a$|b$)", "eca", 0, 3);
    TEST_SEARCH ("d$|c(a$|b$)", "ecb", 0, 3);
    TEST_SEARCH ("d$|c(a$|b$)", "ed", 0, 3);

    TEST_SEARCH ("(((^a|^b))c|^d)e", "acef", 0, 4);
    TEST_SEARCH ("(((^a|^b))c|^d)e", "bcef", 0, 4);
    TEST_SEARCH ("(((^a|^b))c|^d)e", "def", 0, 3);

    TEST_SEARCH ("((^(a|b))c|^d)e", "acef", 0, 4);
    TEST_SEARCH ("((^(a|b))c|^d)e", "bcef", 0, 4);
    TEST_SEARCH ("((^(a|b))c|^d)e", "def", 0, 3);

    TEST_SEARCH ("(^((a|b))c|^d)e", "acef", 0, 4);
    TEST_SEARCH ("(^((a|b))c|^d)e", "bcef", 0, 4);
    TEST_SEARCH ("(^((a|b))c|^d)e", "def", 0, 3);

    TEST_SEARCH ("(((a|b))c|d)e$", "face", 0, 4);
    TEST_SEARCH ("(((a|b))c|d)e$", "fbce", 0, 4);
    TEST_SEARCH ("(((a|b))c|d)e$", "fde", 0, 3);

    TEST_SEARCH ("^e(d|c((a|b)))", "edf", 0, 3);
    TEST_SEARCH ("^e(d|c((a|b)))", "ecaf", 0, 4);
    TEST_SEARCH ("^e(d|c((a|b)))", "ecbf", 0, 4);

    TEST_SEARCH ("e(d$|c((a$|b$)))", "fed", 0, 3);
    TEST_SEARCH ("e(d$|c((a$|b$)))", "feca", 0, 4);
    TEST_SEARCH ("e(d$|c((a$|b$)))", "fecb", 0, 4);

    TEST_SEARCH ("e(d$|c((a|b)$))", "fed", 0, 3);
    TEST_SEARCH ("e(d$|c((a|b)$))", "feca", 0, 4);
    TEST_SEARCH ("e(d$|c((a|b)$))", "fecb", 0, 4);

    TEST_SEARCH ("e(d$|c((a|b))$)", "fed", 0, 3);
    TEST_SEARCH ("e(d$|c((a|b))$)", "feca", 0, 3);
    TEST_SEARCH ("e(d$|c((a|b))$)", "fecb", 0, 3);

    TEST_SEARCH ("e(d$|c((a|b)))$", "fed", 0, 3);
    TEST_SEARCH ("e(d$|c((a|b)))$", "feca", 0, 3);
    TEST_SEARCH ("e(d$|c((a|b)))$", "fecb", 0, 3);

    TEST_SEARCH ("(((^a|^b))c)|^de", "acf", 0, 3);
    TEST_SEARCH ("(((^a|^b))c)|^de", "bcf", 0, 3);
    TEST_SEARCH ("(((^a|^b))c)|^de", "def", 0, 3);

    TEST_SEARCH ("(((a|b))c$)|de$", "fac", 0, 3);
    TEST_SEARCH ("(((a|b))c$)|de$", "fbc", 0, 3);
    TEST_SEARCH ("(((a|b))c$)|de$", "fde", 0, 3);

    TEST_SEARCH ("(((a|b))c)$|de$", "fac", 0, 3);
    TEST_SEARCH ("(((a|b))c)$|de$", "fbc", 0, 3);
    TEST_SEARCH ("(((a|b))c)$|de$", "fde", 0, 3);

    TEST_SEARCH ("^ed|^(c((a|b)))", "edf", 0, 3);
    TEST_SEARCH ("^ed|^(c((a|b)))", "caf", 0, 3);
    TEST_SEARCH ("^ed|^(c((a|b)))", "cbf", 0, 3);

    TEST_SEARCH ("^ed|(^c((a|b)))", "edf", 0, 3);
    TEST_SEARCH ("^ed|(^c((a|b)))", "caf", 0, 3);
    TEST_SEARCH ("^ed|(^c((a|b)))", "cbf", 0, 3);

    TEST_SEARCH ("ed$|(c((a|b)))$", "fed", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b)))$", "fca", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b)))$", "fcb", 0, 3);

    TEST_SEARCH ("ed$|(c((a|b))$)", "fed", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b))$)", "fca", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b))$)", "fcb", 0, 3);

    TEST_SEARCH ("ed$|(c((a|b)$))", "fed", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b)$))", "fca", 0, 3);
    TEST_SEARCH ("ed$|(c((a|b)$))", "fcb", 0, 3);

    TEST_SEARCH ("ed$|(c((a$|b$)))", "fed", 0, 3);
    TEST_SEARCH ("ed$|(c((a$|b$)))", "fca", 0, 3);
    TEST_SEARCH ("ed$|(c((a$|b$)))", "fcb", 0, 3);

    TEST_SEARCH ("^a(b|c)|^d", "abe", 0, 3);
    TEST_SEARCH ("^a(b|c)|^d", "ace", 0, 3);
    TEST_SEARCH ("^a(b|c)|^d", "df", 0, 2);

    TEST_SEARCH ("a(b$|c$)|d$", "fab", 0, 3);
    TEST_SEARCH ("a(b$|c$)|d$", "fac", 0, 3);
    TEST_SEARCH ("a(b$|c$)|d$", "fd", 0, 2);

    TEST_SEARCH ("^(a)(b|c)|^d", "abe", 0, 3);
    TEST_SEARCH ("^(a)(b|c)|^d", "ace", 0, 3);
    TEST_SEARCH ("^(a)(b|c)|^d", "df", 0, 2);

    TEST_SEARCH ("(^a)(b|c)|^d", "abe", 0, 3);
    TEST_SEARCH ("(^a)(b|c)|^d", "ace", 0, 3);
    TEST_SEARCH ("(^a)(b|c)|^d", "df", 0, 2);

    TEST_SEARCH ("(a)(b|c)$|d$", "fab", 0, 3);
    TEST_SEARCH ("(a)(b|c)$|d$", "fac", 0, 3);
    TEST_SEARCH ("(a)(b|c)$|d$", "fd", 0, 2);

    TEST_SEARCH ("(b|c)(a)$|d$", "fba", 0, 3);
    TEST_SEARCH ("(b|c)(a)$|d$", "fca", 0, 3);
    TEST_SEARCH ("(b|c)(a)$|d$", "fd", 0, 2);

    TEST_SEARCH ("(b|c)(a$)|d$", "fba", 0, 3);
    TEST_SEARCH ("(b|c)(a$)|d$", "fca", 0, 3);
    TEST_SEARCH ("(b|c)(a$)|d$", "fd", 0, 2);

    TEST_SEARCH ("(a)(b$|c$)|d$", "fab", 0, 3);
    TEST_SEARCH ("(a)(b$|c$)|d$", "fac", 0, 3);
    TEST_SEARCH ("(a)(b$|c$)|d$", "fd", 0, 2);

    TEST_SEARCH ("^d|^(b|c)(a)", "df", 0, 2);
    TEST_SEARCH ("^d|^(b|c)(a)", "baf", 0, 3);
    TEST_SEARCH ("^d|^(b|c)(a)", "caf", 0, 3);

    TEST_SEARCH ("^d|(^b|^c)(a)", "df", 0, 2);
    TEST_SEARCH ("^d|(^b|^c)(a)", "baf", 0, 3);
    TEST_SEARCH ("^d|(^b|^c)(a)", "caf", 0, 3);

    TEST_SEARCH ("d$|(b|c)(a$)", "fd", 0, 2);
    TEST_SEARCH ("d$|(b|c)(a$)", "fba", 0, 3);
    TEST_SEARCH ("d$|(b|c)(a$)", "fca", 0, 3);

    TEST_SEARCH ("d$|(b|c)(a)$", "fd", 0, 2);
    TEST_SEARCH ("d$|(b|c)(a)$", "fba", 0, 3);
    TEST_SEARCH ("d$|(b|c)(a)$", "fca", 0, 3);

    TEST_SEARCH ("d$|(b|c)(a$)", "fd", 0, 2);
    TEST_SEARCH ("d$|(b|c)(a$)", "fba", 0, 3);
    TEST_SEARCH ("d$|(b|c)(a$)", "fca", 0, 3);

    TEST_SEARCH ("^d|^(a)(b|c)", "df", 0, 2);
    TEST_SEARCH ("^d|^(a)(b|c)", "abf", 0, 3);
    TEST_SEARCH ("^d|^(a)(b|c)", "acf", 0, 3);

    TEST_SEARCH ("^d|(^a)(b|c)", "df", 0, 2);
    TEST_SEARCH ("^d|(^a)(b|c)", "abf", 0, 3);
    TEST_SEARCH ("^d|(^a)(b|c)", "acf", 0, 3);

    TEST_SEARCH ("d$|(a)(b$|c$)", "fd", 0, 2);
    TEST_SEARCH ("d$|(a)(b$|c$)", "fab", 0, 3);
    TEST_SEARCH ("d$|(a)(b$|c$)", "fac", 0, 3);

    TEST_SEARCH ("d$|(a)(b|c)$", "fd", 0, 2);
    TEST_SEARCH ("d$|(a)(b|c)$", "fab", 0, 3);
    TEST_SEARCH ("d$|(a)(b|c)$", "fac", 0, 3);

    TEST_SEARCH ("((^a|^b)|^c)|^d", "ae", 0, 2);
    TEST_SEARCH ("((^a|^b)|^c)|^d", "be", 0, 2);
    TEST_SEARCH ("((^a|^b)|^c)|^d", "ce", 0, 2);
    TEST_SEARCH ("((^a|^b)|^c)|^d", "de", 0, 2);

    TEST_SEARCH ("((a|b)|c)|d$", "ed", 0, 2);
    TEST_SEARCH ("((a|b)|c)|d$", "ea", 0, 2);
    TEST_SEARCH ("((a|b)|c)|d$", "eb", 0, 2);
    TEST_SEARCH ("((a|b)|c)|d$", "ec", 0, 2);

    TEST_SEARCH ("^d|(c|(a|b))", "de", 0, 2);

    TEST_SEARCH ("d$|(c$|(a$|b$))", "ed", 0, 2);
    TEST_SEARCH ("d$|(c$|(a$|b$))", "ec", 0, 2);
    TEST_SEARCH ("d$|(c$|(a$|b$))", "ea", 0, 2);
    TEST_SEARCH ("d$|(c$|(a$|b$))", "eb", 0, 2);

    TEST_SEARCH ("d$|(c$|(a|b)$)", "ed", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b)$)", "ec", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b)$)", "ea", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b)$)", "eb", 0, 2);

    TEST_SEARCH ("d$|(c$|(a|b))$", "ed", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b))$", "ec", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b))$", "ea", 0, 2);
    TEST_SEARCH ("d$|(c$|(a|b))$", "eb", 0, 2);

    test_match ("a|^b", "b");
    test_match ("a|b$", "b");
    test_match ("^b|a", "b");
    test_match ("b$|a", "b");
    test_match ("(^a)", "a");
    test_match ("(a$)", "a");
    TEST_SEARCH ("c|^ab", "aba", 0, 3);
    TEST_SEARCH ("c|ba$", "aba", 0, 3);
    TEST_SEARCH ("^ab|c", "aba", 0, 3);
    TEST_SEARCH ("ba$|c", "aba", 0, 3);
    TEST_SEARCH ("(^a)", "ab", 0, 2);
    TEST_SEARCH ("(a$)", "ba", 0, 2);

    TEST_SEARCH ("(^a$)", "a", 0, 1);
    TEST_SEARCH ("(^a)", "ab", 0, 2);
    TEST_SEARCH ("(b$)", "ab", 0, 2);

    /* Backtracking.  */
    /* Per POSIX D11.1 p. 108, leftmost longest match.  */
    test_match ("(wee|week)(knights|night)", "weeknights");

    test_match ("(fooq|foo)qbar", "fooqbar");
    test_match ("(fooq|foo)(qbarx|bar)", "fooqbarx");

    /* Take first alternative that does the longest match.  */
    test_all_registers ("(fooq|(foo)|(fo))((qbarx)|(oqbarx)|bar)", "fooqbarx",
                        "", 0, 8,  0, 3,  0, 3,  -1, -1,  3, 8,  3, 8,  -1, -1,  -1, -1, -1, -1,
                        -1, -1);

    test_match ("(fooq|foo)*qbar", "fooqbar");
    test_match ("(fooq|foo)*(qbar)", "fooqbar");
    test_match ("(fooq|foo)*(qbar)*", "fooqbar");

    test_match ("(fooq|fo|o)*qbar", "fooqbar");
    test_match ("(fooq|fo|o)*(qbar)", "fooqbar");
    test_match ("(fooq|fo|o)*(qbar)*", "fooqbar");

    test_match ("(fooq|fo|o)*(qbar|q)*", "fooqbar");
    test_match ("(fooq|foo)*(qbarx|bar)", "fooqbarx");
    test_match ("(fooq|foo)*(qbarx|bar)*", "fooqbarx");

    test_match ("(fooq|fo|o)+(qbar|q)+", "fooqbar");
    test_match ("(fooq|foo)+(qbarx|bar)", "fooqbarx");
    test_match ("(fooq|foo)+(qbarx|bar)+", "fooqbarx");

    /* Per Mike Haertel.  */
    test_match ("(foo|foobarfoo)(bar)*", "foobarfoo");

    /* Combination.  */
    test_match ("[ab]?c", "ac");
    test_match ("[ab]*c", "ac");
    test_match ("[ab]+c", "ac");
    test_match ("(a|b)?c", "ac");
    test_match ("(a|b)*c", "ac");
    test_match ("(a|b)+c", "ac");
    test_match ("(a*c)?b", "b");
    test_match ("(a*c)+b", "aacb");
    /* Registers.  */
    /* Per David A. Willcox.  */
    test_match ("a((b)|(c))d", "acd");
    test_all_registers ("a((b)|(c))d", "acd", "", 0, 3, 1, 2, -1, -1, 1, 2,
                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);


    /* Extended regular expressions, continued; these don't match their strings.  */
    test_should_match = false;

#if 0
    /* Invalid use of special characters.  */
    /* These are not invalid anymore, since POSIX says the behavior is
       undefined, and we prefer context-independent to context-invalid.  */
    invalid_pattern (REG_BADRPT, "*");
    invalid_pattern (REG_BADRPT, "a|*");
    invalid_pattern (REG_BADRPT, "(*)");
    invalid_pattern (REG_BADRPT, "^*");
    invalid_pattern (REG_BADRPT, "+");
    invalid_pattern (REG_BADRPT, "a|+");
    invalid_pattern (REG_BADRPT, "(+)");
    invalid_pattern (REG_BADRPT, "^+");

    invalid_pattern (REG_BADRPT, "?");
    invalid_pattern (REG_BADRPT, "a|?");
    invalid_pattern (REG_BADRPT, "(?)");
    invalid_pattern (REG_BADRPT, "^?");

    invalid_pattern (REG_BADPAT, "|");
    invalid_pattern (REG_BADPAT, "a|");
    invalid_pattern (REG_BADPAT, "a||");
    invalid_pattern (REG_BADPAT, "(|a)");
    invalid_pattern (REG_BADPAT, "(a|)");

    invalid_pattern (REG_BADPAT, PARENS_TO_OPS ("(|)"));

    invalid_pattern (REG_BADRPT, "{1}");
    invalid_pattern (REG_BADRPT, "a|{1}");
    invalid_pattern (REG_BADRPT, "^{1}");
    invalid_pattern (REG_BADRPT, "({1})");

    invalid_pattern (REG_BADPAT, "|b");

    invalid_pattern (REG_BADRPT, "^{0,}*");
    invalid_pattern (REG_BADRPT, "$*");
    invalid_pattern (REG_BADRPT, "${0,}*");
#endif /* 0 */

    invalid_pattern (REG_EESCAPE, "\\");

    test_match ("a?b", "a");


    test_match ("a+", "");
    test_match ("a+b", "a");
    test_match ("a?", "b");

#if 0
    /* We make empty groups valid now, since they are undefined in POSIX.
      (13 Sep 92) */
    /* Subexpressions.  */
    invalid_pattern (REG_BADPAT, "()");
    invalid_pattern (REG_BADPAT, "a()");
    invalid_pattern (REG_BADPAT, "()b");
    invalid_pattern (REG_BADPAT, "a()b");
    invalid_pattern (REG_BADPAT, "()*");
    invalid_pattern (REG_BADPAT, "(()*");
#endif
    /* Invalid intervals.  */
    test_match ("a{2}*", "aaa");
    test_match ("a{2}?", "aaa");
    test_match ("a{2}+", "aaa");
    test_match ("a{2}{2}", "aaa");
    test_match ("a{1}{1}{2}", "aaa");
    test_match ("a{1}{1}{2}", "a");
    /* Invalid alternation.  */
    test_match ("a|b", "c");

    TEST_SEARCH ("c|^ba", "aba", 0, 3);
    TEST_SEARCH ("c|ab$", "aba", 0, 3);
    TEST_SEARCH ("^ba|c", "aba", 0, 3);
    TEST_SEARCH ("ab$|c", "aba", 0, 3);
    /* Invalid anchoring.  */
    TEST_SEARCH ("(^a)", "ba", 0, 2);
    TEST_SEARCH ("(b$)", "ba", 0, 2);

    printf ("\nFinished POSIX extended tests.\n");
}
Пример #15
0
Файл: regexp.c Проект: uarka/sed
static void
compile_regex_1 (struct regex *new_regex, int needed_sub)
{
#ifdef REG_PERL
  int errcode;
  errcode = regncomp(&new_regex->pattern, new_regex->re, new_regex->sz,
                     (needed_sub ? 0 : REG_NOSUB)
                     | new_regex->flags
                     | extended_regexp_flags);

  if (errcode)
    {
      char errorbuf[200];
      regerror(errcode, NULL, errorbuf, 200);
      bad_prog(gettext(errorbuf));
    }
#else
  const char *error;
  int syntax = ((extended_regexp_flags & REG_EXTENDED)
                 ? RE_SYNTAX_POSIX_EXTENDED
                 : RE_SYNTAX_POSIX_BASIC);

  syntax &= ~RE_DOT_NOT_NULL;
  syntax |= RE_NO_POSIX_BACKTRACKING;

  switch (posixicity)
    {
    case POSIXLY_EXTENDED:
      syntax &= ~RE_UNMATCHED_RIGHT_PAREN_ORD;
      break;
    case POSIXLY_CORRECT:
      syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD;
      break;
    case POSIXLY_BASIC:
      syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD | RE_LIMITED_OPS | RE_NO_GNU_OPS;
      break;
    }

#ifdef RE_ICASE
  syntax |= (new_regex->flags & REG_ICASE) ? RE_ICASE : 0;
#endif
#ifdef RE_NO_SUB
  syntax |= needed_sub ? 0 : RE_NO_SUB;
#endif

  new_regex->pattern.fastmap = malloc (1 << (sizeof (char) * 8));

  /* If REG_NEWLINE is set, newlines are treated differently.  */
  if (new_regex->flags & REG_NEWLINE)
    {
      /* REG_NEWLINE implies neither . nor [^...] match newline.  */
      syntax &= ~RE_DOT_NEWLINE;
      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
    }

  re_set_syntax (syntax);
  error = re_compile_pattern (new_regex->re, new_regex->sz,
                              &new_regex->pattern);
  new_regex->pattern.newline_anchor = (new_regex->flags & REG_NEWLINE) != 0;

  new_regex->pattern.translate = NULL;
#ifndef RE_ICASE
  if (new_regex->flags & REG_ICASE)
    {
      static char translate[1 << (sizeof(char) * 8)];
      int i;
      for (i = 0; i < sizeof(translate) / sizeof(char); i++)
        translate[i] = tolower (i);

      new_regex->pattern.translate = translate;
    }
#endif

  if (error)
    bad_prog(error);
#endif

  /* Just to be sure, I mark this as not POSIXLY_CORRECT behavior */
  if (needed_sub
      && new_regex->pattern.re_nsub < needed_sub - 1
      && posixicity == POSIXLY_EXTENDED)
    {
      char buf[200];
      sprintf(buf, _("invalid reference \\%d on `s' command's RHS"),
              needed_sub - 1);
      bad_prog(buf);
    }
}
Пример #16
0
int
main (int argc, char *argv[])
{
  int fd;
  struct stat st;
  int result;
  char *inmem;
  char *outmem;
  size_t inlen;
  size_t outlen;

#ifdef HAVE_MCHECK_H
  mtrace ();
#endif

  if (!argv[1])
    exit (1);

  /* Make the content of the file available in memory.  */
  fd = open (argv[1], O_RDONLY);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "cannot open %s", basename (argv[1]));

  if (fstat (fd, &st) != 0)
    error (EXIT_FAILURE, errno, "cannot stat %s", basename (argv[1]));
  memlen = st.st_size;

  mem = (char *) malloc (memlen + 1);
  if (mem == NULL)
    error (EXIT_FAILURE, errno, "while allocating buffer");

  if ((size_t) read (fd, mem, memlen) != memlen)
    error (EXIT_FAILURE, 0, "cannot read entire file");
  mem[memlen] = '\0';

  close (fd);

  /* We have to convert a few things from Latin-1 to UTF-8.  */
  cd = iconv_open ("UTF-8", "ISO-8859-1");
  if (cd == (iconv_t) -1)
    error (EXIT_FAILURE, errno, "cannot get conversion descriptor");

  /* For the second test we have to convert the file content to UTF-8.
     Since the text is mostly ASCII it should be enough to allocate
     twice as much memory for the UTF-8 text than for the Latin-1
     text.  */
  umem = (char *) calloc (2, memlen);
  if (umem == NULL)
    error (EXIT_FAILURE, errno, "while allocating buffer");

  inmem = mem;
  inlen = memlen;
  outmem = umem;
  outlen = 2 * memlen - 1;
  iconv (cd, &inmem, &inlen, &outmem, &outlen);
  umemlen = outmem - umem;
  if (inlen != 0)
    error (EXIT_FAILURE, errno, "cannot convert buffer");

#ifdef DEBUG
  re_set_syntax (RE_DEBUG);
#endif

  /* Run the actual tests.  All tests are run in a single-byte and a
     multi-byte locale.  */
  result = test_expr ("[הבאגיטךםלמסצףעפ�תש�]", 2, 2);
  result |= test_expr ("G.ran", 2, 3);
  result |= test_expr ("G.\\{1\\}ran", 2, 3);
  result |= test_expr ("G.*ran", 3, 44);
  result |= test_expr ("[הבאג]", 0, 0);
  result |= test_expr ("Uddeborg", 2, 2);
  result |= test_expr (".Uddeborg", 2, 2);

  /* Free the resources.  */
  free (umem);
  iconv_close (cd);
  free (mem);

  return result;
}
Пример #17
0
int
main (int argc, char *argv[])
{
  struct stat st;
  static const char *pat[] = {
    ".?.?.?.?.?.?.?argc",
    "(.?)(.?)(.?)(.?)(.?)(.?)(.?)argc",
    "((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
    "((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
    "((((((((((.?))))))))))argc" };

  size_t len;
  int fd;
  int testno, i, j, k, l;
  char *string;
  char *buf;

  if (argc < 2)
    abort ();

  fd = open (argv[1], O_RDONLY);
  if (fd < 0)
    {
      printf ("Couldn't open %s: %s\n", argv[1], strerror (errno));
      abort ();
    }

  if (fstat (fd, &st) < 0)
    {
      printf ("Couldn't fstat %s: %s\n", argv[1], strerror (errno));
      abort ();
    }

  buf = malloc (st.st_size + 1);
  if (buf == NULL)
    {
      printf ("Couldn't allocate buffer: %s\n", strerror (errno));
      abort ();
    }

  if (read (fd, buf, st.st_size) != (ssize_t) st.st_size)
    {
      printf ("Couldn't read %s", argv[1]);
      abort ();
    }

  close (fd);
  buf[st.st_size] = '\0';

  string = buf;
  len = st.st_size;

  for (testno = 0; testno < 4; ++testno)
    for (i = 0; i < sizeof (pat) / sizeof (pat[0]); ++i)
      {
	regex_t rbuf;
	struct re_pattern_buffer rpbuf;
	int err;

	printf ("test %d pattern %d", testno, i);
	if (testno < 2)
	  {
	    err = regcomp (&rbuf, pat[i],
			   REG_EXTENDED | (testno ? REG_NOSUB : 0));
	    if (err != 0)
	      {
		char errstr[300];
		putchar ('\n');
		regerror (err, &rbuf, errstr, sizeof (errstr));
		puts (errstr);
		return err;
	      }
	  }
	else
	  {
	    const char *s;
	    re_set_syntax (RE_SYNTAX_POSIX_EGREP
			   | (testno == 3 ? RE_NO_SUB : 0));

	    memset (&rpbuf, 0, sizeof (rpbuf));
	    s = re_compile_pattern (pat[i], strlen (pat[i]), &rpbuf);
	    if (s != NULL)
	      {
		printf ("\n%s\n", s);
		abort ();
	      }

	    /* Just so that this can be tested with earlier glibc as well.  */
	    if (testno == 3)
	      rpbuf.no_sub = 1;
	  }

      if (testno < 2)
	{
	  regmatch_t pmatch[71];
	  err = regexec (&rbuf, string, 71, pmatch, 0);
	  if (err == REG_NOMATCH)
	    {
	      puts ("\nregexec failed");
	      abort ();
	    }

	  if (testno == 0)
	    {
	      if (pmatch[0].rm_eo != pmatch[0].rm_so + 11
		  || pmatch[0].rm_eo > len
		  || string + pmatch[0].rm_so >= strchr (string, 'R')
		  || strncmp (string + pmatch[0].rm_so,
			      "n (int argc",
			      sizeof "n (int argc" - 1)
		     != 0)
		{
		  puts ("\nregexec without REG_NOSUB did not find the correct match");
		  abort ();
		}

	      if (i > 0)
		for (j = 0, l = 1; j < 7; ++j)
		  for (k = 0; k < (i == 1 ? 1 : 10); ++k, ++l)
		    if (pmatch[l].rm_so != pmatch[0].rm_so + j
			|| pmatch[l].rm_eo != pmatch[l].rm_so + 1)
		      {
			printf ("\npmatch[%d] incorrect\n", l);
			abort ();
		      }
	    }
	}
      else
	{
	  struct re_registers regs;
	  int match;

	  memset (&regs, 0, sizeof (regs));
	  match = re_search (&rpbuf, string, len, 0, len,
				 &regs);
	  if (match < 0)
	    {
	      puts ("\nre_search failed");
	      abort ();
	    }

	  if (match + 11 > len
	      || string + match >= strchr (string, 'R')
	      || strncmp (string + match,
			  "n (int argc",
			  sizeof "n (int argc" - 1)
		  != 0)
	    {
	      puts ("\nre_search did not find the correct match");
	      abort ();
	    }

	  if (testno == 2)
	    {
	      if (regs.num_regs != 2 + (i == 0 ? 0 : i == 1 ? 7 : 70))
		{
		  printf ("\nincorrect num_regs %d\n", regs.num_regs);
		  abort ();
		}

	      if (regs.start[0] != match || regs.end[0] != match + 11)
		{
		  printf ("\nincorrect regs.{start,end}[0] = { %d, %d}\n",
			  regs.start[0], regs.end[0]);
		  abort ();
		}

	      if (regs.start[regs.num_regs - 1] != -1
		  || regs.end[regs.num_regs - 1] != -1)
		{
		  puts ("\nincorrect regs.{start,end}[num_regs - 1]");
		  abort ();
		}

	      if (i > 0)
		for (j = 0, l = 1; j < 7; ++j)
		  for (k = 0; k < (i == 1 ? 1 : 10); ++k, ++l)
		    if (regs.start[l] != match + j
			|| regs.end[l] != regs.start[l] + 1)
		      {
			printf ("\nregs.{start,end}[%d] incorrect\n", l);
			abort ();
		      }
	    }
	}

      putchar ('\n');

      if (testno < 2)
	regfree (&rbuf);
      else
	regfree (&rpbuf);
    }

  exit (0);
}
int
main (void)
{
  struct re_pattern_buffer re;
  char trans[256];
  int i, result = 0;
  const char *s;

  setlocale (LC_ALL, "de_DE.ISO-8859-1");

  for (i = 0; i < 256; ++i)
    trans[i] = tolower (i);

  re_set_syntax (RE_SYNTAX_POSIX_EGREP);

  memset (&re, 0, sizeof (re));
  re.translate = (unsigned char *) trans;
  s = re_compile_pattern ("\\W", 2, &re);

  if (s != NULL)
    {
      printf ("failed to compile pattern \"\\W\": %s\n", s);
      result = 1;
    }
  else
    {
      int ret = re_search (&re, "abc.de", 6, 0, 6, NULL);
      if (ret != 3)
	{
	  printf ("1st re_search returned %d\n", ret);
	  result = 1;
	}

      ret = re_search (&re, "\xc4\xd6\xae\xf7", 4, 0, 4, NULL);
      if (ret != 2)
	{
	  printf ("2nd re_search returned %d\n", ret);
	  result = 1;
	}
      re.translate = NULL;
      regfree (&re);
    }

  memset (&re, 0, sizeof (re));
  re.translate = (unsigned char *) trans;
  s = re_compile_pattern ("\\w", 2, &re);

  if (s != NULL)
    {
      printf ("failed to compile pattern \"\\w\": %s\n", s);
      result = 1;
    }
  else
    {
      int ret = re_search (&re, ".,!abc", 6, 0, 6, NULL);
      if (ret != 3)
	{
	  printf ("3rd re_search returned %d\n", ret);
	  result = 1;
	}

      ret = re_search (&re, "\xae\xf7\xc4\xd6", 4, 0, 4, NULL);
      if (ret != 2)
	{
	  printf ("4th re_search returned %d\n", ret);
	  result = 1;
	}
      re.translate = NULL;
      regfree (&re);
    }

  memset (&re, 0, sizeof (re));
  re.translate = (unsigned char *) trans;
  s = re_compile_pattern ("[[:DIGIT:]]", 11, &re);
  if (s == NULL)
    {
      printf ("compilation of \"[[:DIGIT:]]\" pattern unexpectedly succeeded: %s\n",
	      s);
      result = 1;
    }

  memset (&re, 0, sizeof (re));
  re.translate = (unsigned char *) trans;
  s = re_compile_pattern ("[[:DIGIT:]]", 2, &re);
  if (s == NULL)
    {
      printf ("compilation of \"[[:DIGIT:]]\" pattern unexpectedly succeeded: %s\n",
	      s);
      result = 1;
    }

  return result;
}
Пример #19
0
static void *
compile (const char *pattern, size_t pattern_size,
	 bool match_icase, bool match_words, bool match_lines, char eolbyte,
	 reg_syntax_t syntax)
{
  struct compiled_regex *cregex;
  const char *err;
  const char *sep;
  size_t total = pattern_size;
  const char *motif = pattern;

  cregex = (struct compiled_regex *) xmalloc (sizeof (struct compiled_regex));
  memset (cregex, '\0', sizeof (struct compiled_regex));
  cregex->match_words = match_words;
  cregex->match_lines = match_lines;
  cregex->eolbyte = eolbyte;
  cregex->patterns = NULL;
  cregex->pcount = 0;

  re_set_syntax (syntax);
  dfasyntax (syntax, match_icase, eolbyte);

  /* For GNU regex compiler we have to pass the patterns separately to detect
     errors like "[\nallo\n]\n".  The patterns here are "[", "allo" and "]"
     GNU regex should have raise a syntax error.  The same for backref, where
     the backref should have been local to each pattern.  */
  do
    {
      size_t len;
      sep = memchr (motif, '\n', total);
      if (sep)
	{
	  len = sep - motif;
	  sep++;
	  total -= (len + 1);
	}
      else
	{
	  len = total;
	  total = 0;
	}

      cregex->patterns = xrealloc (cregex->patterns, (cregex->pcount + 1) * sizeof (struct patterns));
      memset (&cregex->patterns[cregex->pcount], '\0', sizeof (struct patterns));

      if ((err = re_compile_pattern (motif, len,
				     &(cregex->patterns[cregex->pcount].regexbuf))) != NULL)
	error (exit_failure, 0, err);
      cregex->pcount++;

      motif = sep;
    } while (sep && total != 0);

  /* In the match_words and match_lines cases, we use a different pattern
     for the DFA matcher that will quickly throw out cases that won't work.
     Then if DFA succeeds we do some hairy stuff using the regex matcher
     to decide whether the match should really count. */
  if (match_words || match_lines)
    {
      /* In the whole-word case, we use the pattern:
	 (^|[^[:alnum:]_])(userpattern)([^[:alnum:]_]|$).
	 In the whole-line case, we use the pattern:
	 ^(userpattern)$.  */

      static const char line_beg[] = "^(";
      static const char line_end[] = ")$";
      static const char word_beg[] = "(^|[^[:alnum:]_])(";
      static const char word_end[] = ")([^[:alnum:]_]|$)";
      char *n = (char *) xmalloc (sizeof word_beg - 1 + pattern_size + sizeof word_end);
      size_t i;
      strcpy (n, match_lines ? line_beg : word_beg);
      i = strlen(n);
      memcpy (n + i, pattern, pattern_size);
      i += pattern_size;
      strcpy (n + i, match_lines ? line_end : word_end);
      i += strlen (n + i);
      pattern = n;
      pattern_size = i;
    }

  dfacomp (pattern, pattern_size, &cregex->dfa, 1);
  kwsmusts (cregex, match_icase, match_words, match_lines, eolbyte);

  return cregex;
}
Пример #20
0
Файл: ne.c Проект: vigna/ne
int main(int argc, char **argv) {

	char *locale = setlocale(LC_ALL, "");
	for(int i = 0; i < 256; i++) localised_up_case[i] = toupper(i);

	if (locale) {
		struct re_pattern_buffer re_pb;
		struct re_registers re_reg;
		memset(&re_pb, 0, sizeof re_pb);
		memset(&re_reg, 0, sizeof re_reg);

		re_pb.translate = localised_up_case;
		re_compile_pattern(LOCALE_REGEX, strlen(LOCALE_REGEX), &re_pb);
		if (re_search(&re_pb, locale, strlen(locale), 0, strlen(locale), &re_reg) >= 0) {
			if (re_reg.start[1] >= 0) io_utf8 = true;
		}
		free(re_reg.start);
		free(re_reg.end);
	}

	bool no_config = false;
	char *macro_name = NULL, *key_bindings_name = NULL, *menu_conf_name = NULL, *startup_prefs_name = DEF_PREFS_NAME;

	char * const skiplist = calloc(argc, 1);
	if (!skiplist) exit(1);  /* We need this many flags. */

	for(int i = 1; i < argc; i++) {

		if (argv[i][0] == '-' && (!strcmp(&argv[i][1], "h") || !strcmp(&argv[i][1], "-help" "\0" VERSION_STRING))) {
			puts(ARG_HELP);
			exit(0);
		}

		/* Special arguments start with two dashes. If we find one, we
		   cancel its entry in argv[], so that it will be skipped when opening
		   the specified files. The only exception is +N for skipping to the
		   N-th line. */

		if (argv[i][0] == '-' && argv[i][1] == '-') {
			if (!argv[i][2]) i++; /* You can use "--" to force the next token to be a filename */
			else if (!strcmp(&argv[i][2], "noconfig") || !strcmp(&argv[i][2], "no-config")) {
				no_config = true;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "noansi") || !strcmp(&argv[i][2], "no-ansi")) {
				ansi = false;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "no-syntax")) {
				do_syntax = false;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "prefs")) {
				if (i < argc-1) {
					startup_prefs_name = argv[i+1];
					skiplist[i] = skiplist[i+1] = 1; /* argv[i] = argv[i+1] = NULL; */
				}
			}
			else if (!strcmp(&argv[i][2], "ansi")) {
				ansi = true;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "utf8")) {
				io_utf8 = true;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "no-utf8")) {
				io_utf8 = false;
				skiplist[i] = 1; /* argv[i] = NULL; */
			}
			else if (!strcmp(&argv[i][2], "macro")) {
				if (i < argc-1) {
					macro_name = argv[i+1];
					skiplist[i] = skiplist[i+1] = 1; /* argv[i] = argv[i+1] = NULL; */
				}
			}
			else if (!strcmp(&argv[i][2], "keys")) {
				if (i < argc-1) {
					key_bindings_name = argv[i+1];
					skiplist[i] = skiplist[i+1] = 1; /* argv[i] = argv[i+1] = NULL; */
				}
			}
			else if (!strcmp(&argv[i][2], "menus")) {
				if (i < argc-1) {
					menu_conf_name = argv[i+1];
					skiplist[i] = skiplist[i+1] = 1; /* argv[i] = argv[i+1] = NULL; */
				}
			}
		}
	}

#ifdef NE_TEST
	/* Dump the builtin menu and key bindings to compare to
	   doc/default.menus and doc/default.keys. */
	int dump_config(void);
	dump_config();
#endif

	/* Unless --noconfig was specified, we try to configure the
	   menus and the keyboard. Note that these functions can exit() on error. */

	if (!no_config) {
		get_menu_configuration(menu_conf_name);
		get_key_bindings(key_bindings_name);
	}

	/* If we cannot even create a buffer, better go... */

	if (!new_buffer()) exit(1);

	/* Now that key_bindings are loaded, try to fix up the message for NOT_FOUND. */
	{
		char *repeat_last_keystroke, *new_not_found;
		if ((repeat_last_keystroke = find_key_strokes(REPEATLAST_A, 1))) {
			if ((new_not_found = malloc(39+strlen(repeat_last_keystroke)))) {
				strcat(strcat(strcpy(new_not_found, "Not Found. (RepeatLast with "), repeat_last_keystroke), " to wrap.)");
				error_msg[NOT_FOUND] = new_not_found;
			}
			free(repeat_last_keystroke);
		}
	}

	clear_buffer(cur_buffer);

	/* The INT_MAX clip always exists, and it is used by the Through command. */

	clip_desc * const cd = alloc_clip_desc(INT_MAX, 0);
	if (!cd) exit(1);

	add_head(&clips, &cd->cd_node);

	/* General terminfo and cursor motion initalization. From here onwards,
	   we cannot exit() lightly. */

	term_init();

	/* We will be always using the last line for the status bar. */

	set_terminal_window(ne_lines-1);

	/* We read in all the key capabilities. */

	read_key_capabilities();

	/* Some initializations of other modules... */

	re_set_syntax(
		RE_CONTEXT_INDEP_ANCHORS |
		RE_CONTEXT_INDEP_OPS     | RE_HAT_LISTS_NOT_NEWLINE |
		RE_NEWLINE_ALT           | RE_NO_BK_PARENS          |
		RE_NO_BK_VBAR            | RE_NO_EMPTY_RANGES
	);

	bool first_file = true;

	load_virtual_extensions();
	load_auto_prefs(cur_buffer, startup_prefs_name);

	buffer *stdin_buffer = NULL;
	if (!isatty(fileno(stdin))) {
		first_file = false;
		const int error = load_fd_in_buffer(cur_buffer, fileno(stdin));
		print_error(error);
		stdin_buffer = cur_buffer;

		if (!(freopen("/dev/tty", "r", stdin))) {
			fprintf(stderr, "Cannot reopen input tty\n");
			abort();
		}
	}

	/* The terminal is prepared for interactive I/O. */

	set_interactive_mode();

	clear_entire_screen();

	/* This function sets fatal_code() as signal interrupt handler
	   for all the dangerous signals (SIGILL, SIGSEGV etc.). */

	set_fatal_code();

	if (argc > 1) {

		/* The first file opened does not need a NEWDOC_A action. Note that
		   file loading can be interrupted (wildcarding can sometimes produce
		   unwanted results). */

		uint64_t first_line = 0, first_col = 0;
		bool binary = false, skip_plus = false, read_only = false;
		stop = false;

		for(int i = 1; i < argc && !stop; i++) {
			if (argv[i] && !skiplist[i]) {
				if (argv[i][0] == '+' && !skip_plus) {       /* looking for "+", or "+N" or "+N,M"  */
					uint64_t tmp_l = INT64_MAX, tmp_c = 0;
					char *d;
					errno = 0;
					if (argv[i][1]) {
						if (isdigit((unsigned char)argv[i][1])) {
							tmp_l = strtoll(argv[i]+1, &d, 10);
							if (!errno) {
								if (*d) {  /* separator between N and M */
									if (isdigit((unsigned char)d[1])) {
										tmp_c = strtoll(d+1, &d, 10);
										if (*d) errno = ERANGE;
									}
									else errno = ERANGE;
								}
							}
						}
						else errno = ERANGE;
					}
					if (!errno) {
						first_line = tmp_l;
						first_col  = tmp_c;
					}
					else {
						skip_plus = true;
						i--;
					}
				}
				else if (!strcmp(argv[i], "--binary")) {
					binary = true;
				}
				else if (!strcmp(argv[i], "--read-only") || !strcmp(argv[i], "--readonly") || !strcmp(argv[i], "--ro")) {
					read_only = true;
				}
				else {
					if (!strcmp(argv[i], "-") && stdin_buffer) {
						stdin_buffer->opt.binary = binary;
						if (read_only) stdin_buffer->opt.read_only = read_only;
						if (first_line) do_action(stdin_buffer, GOTOLINE_A, first_line, NULL);
						if (first_col)  do_action(stdin_buffer, GOTOCOLUMN_A, first_col, NULL);
						stdin_buffer = NULL;
					}
					else {
						if (!strcmp(argv[i], "--")) i++;
						if (!first_file) do_action(cur_buffer, NEWDOC_A, -1, NULL);
						else first_file = false;
						cur_buffer->opt.binary = binary;
						if (i < argc) do_action(cur_buffer, OPEN_A, 0, str_dup(argv[i]));
						if (first_line) do_action(cur_buffer, GOTOLINE_A, first_line, NULL);
						if (first_col)  do_action(cur_buffer, GOTOCOLUMN_A, first_col, NULL);
						if (read_only) cur_buffer->opt.read_only = read_only;
					}
					first_line =
					first_col  = 0;
					skip_plus  =
					binary    =
					read_only  = false;
				}
			}
		}

		free(skiplist);

		/* This call makes current the first specified file. It is called
		   only if more than one buffer exist. */

		if (get_nth_buffer(1)) do_action(cur_buffer, NEXTDOC_A, -1, NULL);

	}

	/* We delay updates. In this way the macro activity does not cause display activity. */

	reset_window();
	delay_update();

	if (macro_name) do_action(cur_buffer, MACRO_A, -1, str_dup(macro_name));
	else if (first_file) {
		/* If there is no file to load, and no macro to execute, we display
		   the "NO WARRANTY" message. */
		about();
	}

	while(true) {
		/* If we are displaying the "NO WARRANTY" info, we should not refresh the
		   window now */
		if (!displaying_info) {
			refresh_window(cur_buffer);
			if (cur_buffer->opt.automatch) automatch_bracket(cur_buffer, true);
		}

		draw_status_bar();
		move_cursor(cur_buffer->cur_y, cur_buffer->cur_x);

		int c = get_key_code();

		if (window_changed_size) {
			print_error(do_action(cur_buffer, REFRESH_A, 0, NULL));
			window_changed_size = displaying_info = false;
			cur_buffer->automatch.shown = 0;
		}

		if (c == INVALID_CHAR) continue; /* Window resizing. */
		const input_class ic = CHAR_CLASS(c);

		if (displaying_info) {
			refresh_window(cur_buffer);
			displaying_info = false;
		}

		if (cur_buffer->automatch.shown) automatch_bracket(cur_buffer, false);

		switch(ic) {
		case INVALID:
			print_error(INVALID_CHARACTER);
			break;

		case ALPHA:
			print_error(do_action(cur_buffer, INSERTCHAR_A, c, NULL));
			break;

		case TAB:
			print_error(do_action(cur_buffer, INSERTTAB_A, 1, NULL));
			break;

		case RETURN:
			print_error(do_action(cur_buffer, INSERTLINE_A, -1, NULL));
			break;

		case COMMAND:
			if (c < 0) c = -c - 1;
			if (key_binding[c]) print_error(execute_command_line(cur_buffer, key_binding[c]));
			break;

		default:
			break;
		}
	}
}
Пример #21
0
int
main (void)
{
  struct re_pattern_buffer regbuf;
  const char *err;
  size_t i;
  int ret = 0;

  mtrace ();

  setlocale (LC_ALL, "de_DE.UTF-8");
  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
    {
      int res, optimized;

      re_set_syntax (tests[i].syntax);
      memset (&regbuf, '\0', sizeof (regbuf));
      err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
                                &regbuf);
      if (err != NULL)
	{
	  printf ("re_compile_pattern failed: %s\n", err);
	  ret = 1;
	  continue;
	}

      /* Check if re_search will be done as multi-byte or single-byte.  */
      optimized = ((re_dfa_t *) regbuf.buffer)->mb_cur_max == 1;
      if (optimized != tests[i].optimize)
        {
          printf ("pattern %zd %soptimized while it should%s be\n",
		  i, optimized ? "" : "not ", tests[i].optimize ? "" : " not");
	  ret = 1;
        }

      int str_len = strlen (tests[i].string);
      res = re_search (&regbuf, tests[i].string, str_len, 0, str_len, NULL);
      if (res != tests[i].res)
	{
	  printf ("re_search %zd failed: %d\n", i, res);
	  ret = 1;
	  regfree (&regbuf);
	  continue;
	}

      res = re_search (&regbuf, tests[i].string, str_len, str_len, -str_len,
		       NULL);
      if (res != tests[i].res)
	{
	  printf ("backward re_search %zd failed: %d\n", i, res);
	  ret = 1;
	  regfree (&regbuf);
	  continue;
	}
      regfree (&regbuf);

      re_set_syntax (tests[i].syntax | RE_ICASE);
      memset (&regbuf, '\0', sizeof (regbuf));
      err = re_compile_pattern (tests[i].pattern, strlen (tests[i].pattern),
                                &regbuf);
      if (err != NULL)
	{
	  printf ("re_compile_pattern failed: %s\n", err);
	  ret = 1;
	  continue;
	}

      /* Check if re_search will be done as multi-byte or single-byte.  */
      optimized = ((re_dfa_t *) regbuf.buffer)->mb_cur_max == 1;
      if (optimized)
        {
          printf ("pattern %zd optimized while it should not be when case insensitive\n",
		  i);
	  ret = 1;
        }

      res = re_search (&regbuf, tests[i].string, str_len, 0, str_len, NULL);
      if (res != tests[i].res)
	{
	  printf ("ICASE re_search %zd failed: %d\n", i, res);
	  ret = 1;
	  regfree (&regbuf);
	  continue;
	}

      res = re_search (&regbuf, tests[i].string, str_len, str_len, -str_len,
		       NULL);
      if (res != tests[i].res)
	{
	  printf ("ICASE backward re_search %zd failed: %d\n", i, res);
	  ret = 1;
	  regfree (&regbuf);
	  continue;
	}
      regfree (&regbuf);
    }

  return ret;
}
Пример #22
0
/* ARGSUSED */
static int
ls_fileproc (void *callerdat, struct file_info *finfo)
{
    Vers_TS *vers;
    char *regex_err;
    Node *p, *n;
    bool isdead;
    const char *filename;

    if (regexp_match)
    {
#ifdef FILENAMES_CASE_INSENSITIVE
	  re_set_syntax (REG_ICASE|RE_SYNTAX_EGREP);
#else
	  re_set_syntax (RE_SYNTAX_EGREP);
#endif
	  if ((regex_err = re_comp (regexp_match)) != NULL)
	  {
	      error (1, 0, "bad regular expression passed to 'ls': %s",
                     regex_err);
	  }
	  if (re_exec (finfo->file) == 0)
	      return 0;				/* no match */
    }

    vers = Version_TS (finfo, NULL, show_tag, show_date, 1, 0);
    /* Skip dead revisions unless specifically requested to do otherwise.
     * We also bother to check for long_format so we can print the state.
     */
    if (vers->vn_rcs && (!show_dead_revs || long_format))
	isdead = RCS_isdead (finfo->rcs, vers->vn_rcs);
    else
	isdead = false;
    if (!vers->vn_rcs || (!show_dead_revs && isdead))
    {
        freevers_ts (&vers);
	return 0;
    }

    p = findnode (callerdat, finfo->update_dir);
    if (!p)
    {
	/* This only occurs when a complete path to a file is specified on the
	 * command line.  Put the file in the root list.
	 */
	filename = finfo->fullname;

	/* Add update_dir node.  */
	p = findnode (callerdat, ".");
	if (!p)
	{
	    p = getnode ();
	    p->key = xstrdup (".");
	    p->data = getlist ();
	    p->delproc = ls_delproc;
	    addnode (callerdat, p);
	}
    }
    else
	filename = finfo->file;

    n = getnode();
    if (entries_format)
    {
	char *outdate = entries_time (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
                                                      0, 0));
	n->data = Xasprintf ("/%s/%s/%s/%s/%s%s\n",
                             filename, vers->vn_rcs,
                             outdate, vers->options,
                             show_tag ? "T" : "", show_tag ? show_tag : "");
	free (outdate);
    }
    else if (long_format)
    {
	struct long_format_data *out =
		xmalloc (sizeof (struct long_format_data));
	out->header = Xasprintf ("%-5.5s",
                                 vers->options[0] != '\0' ? vers->options
                                                          : "----");
	/* FIXME: Do we want to mimc the real `ls' command's date format?  */
	out->time = gmformat_time_t (RCS_getrevtime (finfo->rcs, vers->vn_rcs,
                                                     0, 0));
	out->footer = Xasprintf (" %-9.9s%s %s%s", vers->vn_rcs,
                                 strlen (vers->vn_rcs) > 9 ? "+" : " ",
                                 show_dead_revs ? (isdead ? "dead " : "     ")
                                                : "",
                                 filename);
	n->data = out;
	n->delproc = long_format_data_delproc;
    }
    else
	n->data = Xasprintf ("%s\n", filename);

    addnode (p->data, n);

    freevers_ts (&vers);
    return 0;
}
Пример #23
0
void
GEAcompile (char const *pattern, size_t size, reg_syntax_t syntax_bits)
{
  const char *err;
  const char *p, *sep;
  size_t total = size;
  char *motif;

  if (match_icase)
    syntax_bits |= RE_ICASE;
  re_set_syntax (syntax_bits);
  dfasyntax (syntax_bits, match_icase, eolbyte);

  /* For GNU regex compiler we have to pass the patterns separately to detect
     errors like "[\nallo\n]\n".  The patterns here are "[", "allo" and "]"
     GNU regex should have raise a syntax error.  The same for backref, where
     the backref should have been local to each pattern.  */
  p = pattern;
  do
    {
      size_t len;
      sep = memchr (p, '\n', total);
      if (sep)
        {
          len = sep - p;
          sep++;
          total -= (len + 1);
        }
      else
        {
          len = total;
          total = 0;
        }

      patterns = xnrealloc (patterns, pcount + 1, sizeof *patterns);
      patterns[pcount] = patterns0;

      if ((err = re_compile_pattern (p, len,
                                    &(patterns[pcount].regexbuf))) != NULL)
        error (EXIT_TROUBLE, 0, "%s", err);
      pcount++;

      p = sep;
    } while (sep && total != 0);

  /* In the match_words and match_lines cases, we use a different pattern
     for the DFA matcher that will quickly throw out cases that won't work.
     Then if DFA succeeds we do some hairy stuff using the regex matcher
     to decide whether the match should really count. */
  if (match_words || match_lines)
    {
      static char const line_beg_no_bk[] = "^(";
      static char const line_end_no_bk[] = ")$";
      static char const word_beg_no_bk[] = "(^|[^[:alnum:]_])(";
      static char const word_end_no_bk[] = ")([^[:alnum:]_]|$)";
      static char const line_beg_bk[] = "^\\(";
      static char const line_end_bk[] = "\\)$";
      static char const word_beg_bk[] = "\\(^\\|[^[:alnum:]_]\\)\\(";
      static char const word_end_bk[] = "\\)\\([^[:alnum:]_]\\|$\\)";
      int bk = !(syntax_bits & RE_NO_BK_PARENS);
      char *n = xmalloc (sizeof word_beg_bk - 1 + size + sizeof word_end_bk);

      strcpy (n, match_lines ? (bk ? line_beg_bk : line_beg_no_bk)
                             : (bk ? word_beg_bk : word_beg_no_bk));
      total = strlen(n);
      memcpy (n + total, pattern, size);
      total += size;
      strcpy (n + total, match_lines ? (bk ? line_end_bk : line_end_no_bk)
                                     : (bk ? word_end_bk : word_end_no_bk));
      total += strlen (n + total);
      pattern = motif = n;
      size = total;
    }
  else
    motif = NULL;

  dfa = dfaalloc ();
  dfacomp (pattern, size, dfa, 1);
  kwsmusts ();

  free(motif);
}
Пример #24
0
static void
compile_regex_1 (struct regex *new_regex, int needed_sub)
{
  const char *error;
  int syntax = ((extended_regexp_flags & REG_EXTENDED)
                 ? RE_SYNTAX_POSIX_EXTENDED
                 : RE_SYNTAX_POSIX_BASIC);

  syntax &= ~RE_DOT_NOT_NULL;
  syntax |= RE_NO_POSIX_BACKTRACKING;

  switch (posixicity)
    {
    case POSIXLY_EXTENDED:
      syntax &= ~RE_UNMATCHED_RIGHT_PAREN_ORD;
      break;
    case POSIXLY_CORRECT:
      syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD;
      break;
    case POSIXLY_BASIC:
      syntax |= RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS;
      if (!(extended_regexp_flags & REG_EXTENDED))
        syntax |= RE_LIMITED_OPS;
      break;
    }

  if (new_regex->flags & REG_ICASE)
    syntax |= RE_ICASE;
  else
    new_regex->pattern.fastmap = malloc (1 << (sizeof (char) * 8));
  syntax |= needed_sub ? 0 : RE_NO_SUB;

  /* If REG_NEWLINE is set, newlines are treated differently.  */
  if (new_regex->flags & REG_NEWLINE)
    {
      /* REG_NEWLINE implies neither . nor [^...] match newline.  */
      syntax &= ~RE_DOT_NEWLINE;
      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
    }

  re_set_syntax (syntax);
  error = re_compile_pattern (new_regex->re, new_regex->sz,
                              &new_regex->pattern);
  new_regex->pattern.newline_anchor =
    buffer_delimiter == '\n' && (new_regex->flags & REG_NEWLINE) != 0;

  new_regex->pattern.translate = NULL;
#ifndef RE_ICASE
  if (new_regex->flags & REG_ICASE)
    {
      static char translate[1 << (sizeof (char) * 8)];
      int i;
      for (i = 0; i < sizeof (translate) / sizeof (char); i++)
        translate[i] = tolower (i);

      new_regex->pattern.translate = translate;
    }
#endif

  if (error)
    bad_prog (error);

  /* Just to be sure, I mark this as not POSIXLY_CORRECT behavior */
  if (needed_sub
      && new_regex->pattern.re_nsub < needed_sub - 1
      && posixicity == POSIXLY_EXTENDED)
    {
      char buf[200];
      sprintf (buf, _("invalid reference \\%d on `s' command's RHS"),
              needed_sub - 1);
      bad_prog (buf);
    }

  int dfaopts = buffer_delimiter == '\n' ? 0 : DFA_EOL_NUL;
  new_regex->dfa = dfaalloc ();
  dfasyntax (new_regex->dfa, &localeinfo, syntax, dfaopts);
  dfacomp (new_regex->re, new_regex->sz, new_regex->dfa, 1);

  /* The patterns which consist of only ^ or $ often appear in
     substitution, but regex and dfa are not good at them, as regex does
     not build fastmap, and as all in buffer must be scanned for $.  So
     we mark them to handle manually.  */
  if (new_regex->sz == 1)
    {
      if (new_regex->re[0] == '^')
        new_regex->begline = true;
      if (new_regex->re[0] == '$')
        new_regex->endline = true;
    }
}
Пример #25
0
Файл: re.c Проект: WndSks/msys
Regexp *
make_regexp(const char *s, size_t len, int ignorecase, int dfa)
{
	Regexp *rp;
	const char *rerr;
	const char *src = s;
	char *temp;
	const char *end = s + len;
	register char *dest;
	register int c, c2;
	static short first = TRUE;
	static short no_dfa = FALSE;
	int has_anchor = FALSE;

	/* The number of bytes in the current multibyte character.
	   It is 0, when the current character is a singlebyte character.  */
	size_t is_multibyte = 0;
#ifdef MBS_SUPPORT
	mbstate_t mbs;

	if (gawk_mb_cur_max > 1)
		memset(&mbs, 0, sizeof(mbstate_t)); /* Initialize.  */
#endif

	if (first) {
		first = FALSE;
		no_dfa = (getenv("GAWK_NO_DFA") != NULL);	/* for debugging and testing */
	}

	/* Handle escaped characters first. */

	/*
	 * Build a copy of the string (in dest) with the
	 * escaped characters translated, and generate the regex
	 * from that.  
	 */
	emalloc(dest, char *, len + 2, "make_regexp");
	temp = dest;

	while (src < end) {
#ifdef MBS_SUPPORT
		if (gawk_mb_cur_max > 1 && ! is_multibyte) {
			/* The previous byte is a singlebyte character, or last byte
			   of a multibyte character.  We check the next character.  */
			is_multibyte = mbrlen(src, end - src, &mbs);
			if ((is_multibyte == 1) || (is_multibyte == (size_t) -1)
				|| (is_multibyte == (size_t) -2 || (is_multibyte == 0))) {
				/* We treat it as a singlebyte character.  */
				is_multibyte = 0;
			}
		}
#endif

		/* We skip multibyte character, since it must not be a special
		   character.  */
		if ((gawk_mb_cur_max == 1 || ! is_multibyte) &&
		    (*src == '\\')) {
			c = *++src;
			switch (c) {
			case 'a':
			case 'b':
			case 'f':
			case 'n':
			case 'r':
			case 't':
			case 'v':
			case 'x':
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
				c2 = parse_escape(&src);
				if (c2 < 0)
					cant_happen();
				/*
				 * Unix awk treats octal (and hex?) chars
				 * literally in re's, so escape regexp
				 * metacharacters.
				 */
				if (do_traditional && ! do_posix && (ISDIGIT(c) || c == 'x')
				    && strchr("()|*+?.^$\\[]", c2) != NULL)
					*dest++ = '\\';
				*dest++ = (char) c2;
				break;
			case '8':
			case '9':	/* a\9b not valid */
				*dest++ = c;
				src++;
				break;
			case 'y':	/* normally \b */
				/* gnu regex op */
				if (! do_traditional) {
					*dest++ = '\\';
					*dest++ = 'b';
					src++;
					break;
				}
				/* else, fall through */
			default:
				*dest++ = '\\';
				*dest++ = (char) c;
				src++;
				break;
			} /* switch */
		} else {
			c = *src;
			if (c == '^' || c == '$')
				has_anchor = TRUE;
			*dest++ = *src++;	/* not '\\' */
		}
		if (gawk_mb_cur_max > 1 && is_multibyte)
			is_multibyte--;
	} /* while */

	*dest = '\0' ;	/* Only necessary if we print dest ? */
	emalloc(rp, Regexp *, sizeof(*rp), "make_regexp");
	memset((char *) rp, 0, sizeof(*rp));
	rp->pat.allocated = 0;	/* regex will allocate the buffer */
	emalloc(rp->pat.fastmap, char *, 256, "make_regexp");

	/*
	 * Lo these many years ago, had I known what a P.I.T.A. IGNORECASE
	 * was going to turn out to be, I wouldn't have bothered with it.
	 *
	 * In the case where we have a multibyte character set, we have no
	 * choice but to use RE_ICASE, since the casetable is for single-byte
	 * character sets only.
	 *
	 * On the other hand, if we do have a single-byte character set,
	 * using the casetable should give  a performance improvement, since
	 * it's computed only once, not each time a regex is compiled.  We
	 * also think it's probably better for portability.  See the
	 * discussion by the definition of casetable[] in eval.c.
	 */

	if (ignorecase) {
		if (gawk_mb_cur_max > 1) {
			syn |= RE_ICASE;
			rp->pat.translate = NULL;
		} else {
			syn &= ~RE_ICASE;
			rp->pat.translate = (char *) casetable;
		}
	} else {
		rp->pat.translate = NULL;
		syn &= ~RE_ICASE;
	}

	dfasyntax(syn | (ignorecase ? RE_ICASE : 0), ignorecase ? TRUE : FALSE, '\n');
	re_set_syntax(syn);

	len = dest - temp;
	if ((rerr = re_compile_pattern(temp, len, &(rp->pat))) != NULL)
		fatal("%s: /%s/", rerr, temp);	/* rerr already gettextized inside regex routines */

	/* gack. this must be done *after* re_compile_pattern */
	rp->pat.newline_anchor = FALSE; /* don't get \n in middle of string */
	if (dfa && ! no_dfa) {
		dfacomp(temp, len, &(rp->dfareg), TRUE);
		rp->dfa = TRUE;
	} else
		rp->dfa = FALSE;
	rp->has_anchor = has_anchor;

	free(temp);
	return rp;
}
Пример #26
0
int
main (void)
{
  const char *file;
  int fd;
  struct stat st;
  int result;
  char *inmem;
  char *outmem;
  size_t inlen;
  size_t outlen;

  mtrace ();

  /* Make the content of the file available in memory.  */
  file = "../ChangeLog.8";
  fd = open (file, O_RDONLY);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "cannot open %s", basename (file));

  if (fstat (fd, &st) != 0)
    error (EXIT_FAILURE, errno, "cannot stat %s", basename (file));
  memlen = st.st_size;

  mem = (char *) malloc (memlen + 1);
  if (mem == NULL)
    error (EXIT_FAILURE, errno, "while allocating buffer");

  if (read (fd, mem, memlen) != memlen)
    error (EXIT_FAILURE, 0, "cannot read entire file");
  mem[memlen] = '\0';

  close (fd);

  /* We have to convert a few things from Latin-1 to UTF-8.  */
  cd = iconv_open ("UTF-8", "ISO-8859-1");
  if (cd == (iconv_t) -1)
    error (EXIT_FAILURE, errno, "cannot get conversion descriptor");

  /* For the second test we have to convert the file content to UTF-8.
     Since the text is mostly ASCII it should be enough to allocate
     twice as much memory for the UTF-8 text than for the Latin-1
     text.  */
  umem = (char *) calloc (2, memlen);
  if (umem == NULL)
    error (EXIT_FAILURE, errno, "while allocating buffer");

  inmem = mem;
  inlen = memlen;
  outmem = umem;
  outlen = 2 * memlen - 1;
  iconv (cd, &inmem, &inlen, &outmem, &outlen);
  if (inlen != 0)
    error (EXIT_FAILURE, errno, "cannot convert buffer");

#ifdef _POSIX_CPUTIME
  /* See whether we can use the CPU clock.  */
  use_clock = clock_getcpuclockid (0, &cl) == 0;
#endif

#ifdef DEBUG
  re_set_syntax (RE_DEBUG);
#endif

  /* Run the actual tests.  All tests are run in a single-byte and a
     multi-byte locale.  */
  result = test_expr ("[הבאגיטךםלמסצףעפ�תש�]", 2);
  result |= test_expr ("G.ran", 2);
  result |= test_expr ("G.\\{1\\}ran", 2);
  result |= test_expr ("G.*ran", 3);
  result |= test_expr ("[הבאג]", 0);

  /* Free the resources.  */
  free (umem);
  iconv_close (cd);
  free (mem);

  return result;
}
Пример #27
0
int
main (void)
{
  int result = 0;
  static struct re_pattern_buffer regex;
  unsigned char folded_chars[UCHAR_MAX + 1];
  int i;
  const char *s;
  struct re_registers regs;

#if HAVE_DECL_ALARM
  /* Some builds of glibc go into an infinite loop on this test.  */
  int alarm_value = 2;
  signal (SIGALRM, SIG_DFL);
  alarm (alarm_value);
#endif
  if (setlocale (LC_ALL, "en_US.UTF-8"))
    {
      {
        /* http://sourceware.org/ml/libc-hacker/2006-09/msg00008.html
           This test needs valgrind to catch the bug on Debian
           GNU/Linux 3.1 x86, but it might catch the bug better
           on other platforms and it shouldn't hurt to try the
           test here.  */
        static char const pat[] = "insert into";
        static char const data[] =
          "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK";
        re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE
                       | RE_ICASE);
        memset (&regex, 0, sizeof regex);
        s = re_compile_pattern (pat, sizeof pat - 1, &regex);
        if (s)
          result |= 1;
        else if (re_search (&regex, data, sizeof data - 1,
                            0, sizeof data - 1, &regs)
                 != -1)
          result |= 1;
      }

      /* Check whether it's really a UTF-8 locale.
         On mingw, the setlocale call succeeds but returns
         "English_United States.1252", with locale_charset() returning
         "CP1252".  */
      if (strcmp (locale_charset (), "UTF-8") == 0)
        {
          /* This test is from glibc bug 15078.
             The test case is from Andreas Schwab in
             <http://www.sourceware.org/ml/libc-alpha/2013-01/msg00967.html>.
          */
          static char const pat[] = "[^x]x";
          static char const data[] =
            /* <U1000><U103B><U103D><U1014><U103A><U102F><U1015><U103A> */
            "\xe1\x80\x80"
            "\xe1\x80\xbb"
            "\xe1\x80\xbd"
            "\xe1\x80\x94"
            "\xe1\x80\xba"
            "\xe1\x80\xaf"
            "\xe1\x80\x95"
            "\xe1\x80\xba"
            "x";
          re_set_syntax (0);
          memset (&regex, 0, sizeof regex);
          s = re_compile_pattern (pat, sizeof pat - 1, &regex);
          if (s)
            result |= 1;
          else
            {
              i = re_search (&regex, data, sizeof data - 1,
                             0, sizeof data - 1, 0);
              if (i != 0 && i != 21)
                result |= 1;
            }
        }

      if (! setlocale (LC_ALL, "C"))
        return 1;
    }

  /* This test is from glibc bug 3957, reported by Andrew Mackey.  */
  re_set_syntax (RE_SYNTAX_EGREP | RE_HAT_LISTS_NOT_NEWLINE);
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("a[^x]b", 6, &regex);
  if (s)
    result |= 2;
  /* This should fail, but succeeds for glibc-2.5.  */
  else if (re_search (&regex, "a\nb", 3, 0, 3, &regs) != -1)
    result |= 2;

  /* This regular expression is from Spencer ere test number 75
     in grep-2.3.  */
  re_set_syntax (RE_SYNTAX_POSIX_EGREP);
  memset (&regex, 0, sizeof regex);
  for (i = 0; i <= UCHAR_MAX; i++)
    folded_chars[i] = i;
  regex.translate = folded_chars;
  s = re_compile_pattern ("a[[:@:>@:]]b\n", 11, &regex);
  /* This should fail with _Invalid character class name_ error.  */
  if (!s)
    result |= 4;

  /* Ensure that [b-a] is diagnosed as invalid, when
     using RE_NO_EMPTY_RANGES. */
  re_set_syntax (RE_SYNTAX_POSIX_EGREP | RE_NO_EMPTY_RANGES);
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("a[b-a]", 6, &regex);
  if (s == 0)
    result |= 8;

  /* This should succeed, but does not for glibc-2.1.3.  */
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("{1", 2, &regex);
  if (s)
    result |= 8;

  /* The following example is derived from a problem report
     against gawk from Jorge Stolfi <*****@*****.**>.  */
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("[an\371]*n", 7, &regex);
  if (s)
    result |= 8;
  /* This should match, but does not for glibc-2.2.1.  */
  else if (re_match (&regex, "an", 2, 0, &regs) != 2)
    result |= 8;

  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("x", 1, &regex);
  if (s)
    result |= 8;
  /* glibc-2.2.93 does not work with a negative RANGE argument.  */
  else if (re_search (&regex, "wxy", 3, 2, -2, &regs) != 1)
    result |= 8;

  /* The version of regex.c in older versions of gnulib
     ignored RE_ICASE.  Detect that problem too.  */
  re_set_syntax (RE_SYNTAX_EMACS | RE_ICASE);
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("x", 1, &regex);
  if (s)
    result |= 16;
  else if (re_search (&regex, "WXY", 3, 0, 3, &regs) < 0)
    result |= 16;

  /* Catch a bug reported by Vin Shelton in
     http://lists.gnu.org/archive/html/bug-coreutils/2007-06/msg00089.html
     */
  re_set_syntax (RE_SYNTAX_POSIX_BASIC
                 & ~RE_CONTEXT_INVALID_DUP
                 & ~RE_NO_EMPTY_RANGES);
  memset (&regex, 0, sizeof regex);
  s = re_compile_pattern ("[[:alnum:]_-]\\\\+$", 16, &regex);
  if (s)
    result |= 32;

  /* REG_STARTEND was added to glibc on 2004-01-15.
     Reject older versions.  */
  if (! REG_STARTEND)
    result |= 64;

#if 0
  /* It would be nice to reject hosts whose regoff_t values are too
     narrow (including glibc on hosts with 64-bit ptrdiff_t and
     32-bit int), but we should wait until glibc implements this
     feature.  Otherwise, support for equivalence classes and
     multibyte collation symbols would always be broken except
     when compiling --without-included-regex.   */
  if (sizeof (regoff_t) < sizeof (ptrdiff_t)
      || sizeof (regoff_t) < sizeof (ssize_t))
    result |= 64;
#endif

  return result;
}
Пример #28
0
status_t
Keymap::LoadSource(FILE* file)
{
	// Setup regexp parser

	reg_syntax_t syntax = RE_CHAR_CLASSES;
	re_set_syntax(syntax);

	const char* error = re_compile_pattern(versionPattern,
		strlen(versionPattern), &versionBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(capslockPattern, strlen(capslockPattern),
		&capslockBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(scrolllockPattern, strlen(scrolllockPattern),
		&scrolllockBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(numlockPattern, strlen(numlockPattern),
		&numlockBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(lshiftPattern, strlen(lshiftPattern), &lshiftBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(rshiftPattern, strlen(rshiftPattern), &rshiftBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(lcommandPattern, strlen(lcommandPattern),
		&lcommandBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(rcommandPattern, strlen(rcommandPattern),
		&rcommandBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(lcontrolPattern, strlen(lcontrolPattern),
		&lcontrolBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(rcontrolPattern, strlen(rcontrolPattern),
		&rcontrolBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(loptionPattern, strlen(loptionPattern),
		&loptionBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(roptionPattern, strlen(roptionPattern),
		&roptionBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(menuPattern, strlen(menuPattern), &menuBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(locksettingsPattern, strlen(locksettingsPattern),
		&locksettingsBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(keyPattern, strlen(keyPattern), &keyBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(acutePattern, strlen(acutePattern), &acuteBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(gravePattern, strlen(gravePattern), &graveBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(circumflexPattern, strlen(circumflexPattern),
		&circumflexBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(diaeresisPattern, strlen(diaeresisPattern),
		&diaeresisBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(tildePattern, strlen(tildePattern), &tildeBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(acutetabPattern, strlen(acutetabPattern),
		&acutetabBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(gravetabPattern, strlen(gravetabPattern),
		&gravetabBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(circumflextabPattern,
		strlen(circumflextabPattern), &circumflextabBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(diaeresistabPattern, strlen(diaeresistabPattern),
		&diaeresistabBuf);
	if (error)
		fprintf(stderr, error);
	error = re_compile_pattern(tildetabPattern, strlen(tildetabPattern),
		&tildetabBuf);
	if (error)
		fprintf(stderr, error);

	// Read file

	delete[] fChars;
	fChars = new char[CHARS_TABLE_MAXSIZE];
	fCharsSize = CHARS_TABLE_MAXSIZE;
	int offset = 0;
	int acuteOffset = 0;
	int graveOffset = 0;
	int circumflexOffset = 0;
	int diaeresisOffset = 0;
	int tildeOffset = 0;

	int32* maps[] = {
		fKeys.normal_map,
		fKeys.shift_map,
		fKeys.control_map,
		fKeys.option_map,
		fKeys.option_shift_map,
		fKeys.caps_map,
		fKeys.caps_shift_map,
		fKeys.option_caps_map,
		fKeys.option_caps_shift_map
	};

	char buffer[1024];

	while (fgets(buffer, sizeof(buffer) - 1, file) != NULL) {
		if (buffer[0] == '#' || buffer[0] == '\n')
			continue;

		size_t length = strlen(buffer);

		struct re_registers regs;
		if (re_search(&versionBuf, buffer, length, 0, length, &regs) >= 0) {
			sscanf(buffer + regs.start[1], "%" B_SCNu32, &fKeys.version);
		} else if (re_search(&capslockBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.caps_key);
		} else if (re_search(&scrolllockBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.scroll_key);
		} else if (re_search(&numlockBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.num_key);
		} else if (re_search(&lshiftBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.left_shift_key);
		} else if (re_search(&rshiftBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.right_shift_key);
		} else if (re_search(&lcommandBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.left_command_key);
		} else if (re_search(&rcommandBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.right_command_key);
		} else if (re_search(&lcontrolBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.left_control_key);
		} else if (re_search(&rcontrolBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.right_control_key);
		} else if (re_search(&loptionBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.left_option_key);
		} else if (re_search(&roptionBuf, buffer, length, 0, length, &regs)
				>= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32,
				&fKeys.right_option_key);
		} else if (re_search(&menuBuf, buffer, length, 0, length, &regs) >= 0) {
			sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.menu_key);
		} else if (re_search(&locksettingsBuf, buffer, length, 0, length, &regs)
				>= 0) {
			fKeys.lock_settings = 0;
			for (int32 i = 1; i <= 3; i++) {
				const char* start = buffer + regs.start[i];
				length = regs.end[i] - regs.start[i];
				if (length == 0)
					break;

				if (!strncmp(start, "CapsLock", length))
					fKeys.lock_settings |= B_CAPS_LOCK;
				else if (!strncmp(start, "NumLock", length))
					fKeys.lock_settings |= B_NUM_LOCK;
				else if (!strncmp(start, "ScrollLock", length))
					fKeys.lock_settings |= B_SCROLL_LOCK;
			}
		} else if (re_search(&keyBuf, buffer, length, 0, length, &regs) >= 0) {
			uint32 keyCode;
			if (sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &keyCode) > 0) {
				for (int i = 2; i <= 10; i++) {
					maps[i - 2][keyCode] = offset;
					_ComputeChars(buffer, regs, i, offset);
				}
			}
		} else if (re_search(&acuteBuf, buffer, length, 0, length, &regs) >= 0) {
			for (int i = 1; i <= 2; i++) {
				fKeys.acute_dead_key[acuteOffset++] = offset;
				_ComputeChars(buffer, regs, i, offset);
			}
		} else if (re_search(&graveBuf, buffer, length, 0, length, &regs) >= 0) {
			for (int i = 1; i <= 2; i++) {
				fKeys.grave_dead_key[graveOffset++] = offset;
				_ComputeChars(buffer, regs, i, offset);
			}
		} else if (re_search(&circumflexBuf, buffer, length, 0, length, &regs)
				>= 0) {
			for (int i = 1; i <= 2; i++) {
				fKeys.circumflex_dead_key[circumflexOffset++] = offset;
				_ComputeChars(buffer, regs, i, offset);
			}
		} else if (re_search(&diaeresisBuf, buffer, length, 0, length, &regs)
				>= 0) {
			for (int i = 1; i <= 2; i++) {
				fKeys.dieresis_dead_key[diaeresisOffset++] = offset;
				_ComputeChars(buffer, regs, i, offset);
			}
		} else if (re_search(&tildeBuf, buffer, length, 0, length, &regs) >= 0) {
			for (int i = 1; i <= 2; i++) {
				fKeys.tilde_dead_key[tildeOffset++] = offset;
				_ComputeChars(buffer, regs, i, offset);
			}
		} else if (re_search(&acutetabBuf, buffer, length, 0, length, &regs)
				>= 0) {
			_ComputeTables(buffer, regs, fKeys.acute_tables);
		} else if (re_search(&gravetabBuf, buffer, length, 0, length, &regs)
				>= 0) {
			_ComputeTables(buffer, regs, fKeys.grave_tables);
		} else if (re_search(&circumflextabBuf, buffer, length, 0, length, &regs)
				>= 0) {
			_ComputeTables(buffer, regs, fKeys.circumflex_tables);
		} else if (re_search(&diaeresistabBuf, buffer, length, 0, length, &regs)
				>= 0) {
			_ComputeTables(buffer, regs, fKeys.dieresis_tables);
		} else if (re_search(&tildetabBuf, buffer, length, 0, length, &regs)
				>= 0) {
			_ComputeTables(buffer, regs, fKeys.tilde_tables);
		}
	}

	fCharsSize = offset;

	if (fKeys.version != 3)
		return KEYMAP_ERROR_UNKNOWN_VERSION;

	return B_OK;
}
Пример #29
0
int compile_fast_regex( fast_regex_t * fre_t, const char * sre, size_t len )
{
	struct _fregex * fre = (struct _fregex *)( fre_t->data ) ;

	int errval ;
	char * errstr ;
	int sublen ;
	char * substr ;
	
	errval = 0 ;

		/*	fprintf( stderr, "compile_fast_regex( %p[%p] , %s )\n", fre_t, fre->kwset, sre ) ; */

	if( fast_regex_subsys_error == NULL )
		fast_regex_subsys_error = fprintf_error ;
	
	if( fre_t->options & FRE_STRING_SEARCH )
	{
		if( fre_t->options & FRE_NO_KWSET )
		{
			return -1 ;
		}
			
		/*
		 * straight string match
		 * 'sre' represents a series of newline separated strings to search for
		 */
		while( sre )
		{
			substr = strchr( sre, '\n' ) ;
			if( substr == NULL )
				sublen = len ;
			else
				sublen = (substr - sre) ;

			errstr = kwsincr( fre->kwset, sre, sublen );
			if( errstr )
			{
				errval = (*fast_regex_subsys_error)( "kwset" , errstr ) ;
				if( errval )
					return errval ;
			}
			else
				fre->num_exact_kws ++ ;
		
			len -= (sublen+1) ;
			sre = (substr) ? (substr + 1) : NULL ;
		}
		errstr = kwsprep( fre->kwset );
		if( errstr )
		{
			errval = (*fast_regex_subsys_error)( "kwset", errstr ) ;
			if( errval )
				return errval ;
		}
		return 0 ;
	}
	
	if( HAS_DFA(fre_t->options) || HAS_KWSET(fre_t->options) )
	{
		dfasyntax( RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE, ( fre_t->options & FRE_CASE_INSENSITIVE ) ) ;
		dfacomp( sre, len, &(fre->dfa), 1 ) ;

		if( HAS_KWSET(fre_t->options) )
		{
			errval = build_kws_from_dfa( fre ) ;
			if( fre_t->options & FRE_NO_DFA )
			{  /* We used the DFA only to get the keywords */
				dfafree( &(fre->dfa) );
			}
		}
		else
		{
			fre->kwset = 0 ;
		}
	}

	if( errval )
		return errval ;

	if( HAS_REGEX(fre_t->options) )
	{
		re_set_syntax(RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE);
		errstr = re_compile_pattern( sre, len, &(fre->regex) ) ;
		if( errstr )
		{
			errval = (*fast_regex_subsys_error)( "re", errstr ) ;
			if( errval )
				return errval ;
		}
	}
	
	return errval ;
}		
Пример #30
0
static int
do_test(void)
{
	static const char *pat[] = {
		".?.?.?.?.?.?.?Log\\.13",
		"(.?)(.?)(.?)(.?)(.?)(.?)(.?)Log\\.13",
		"((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
		"((((((((((.?))))))))))((((((((((.?))))))))))((((((((((.?))))))))))"
		"((((((((((.?))))))))))Log\\.13"
	};
	char *buf, *string;
	const char *fname = "tst-regex2.dat";
	struct stat st;
	unsigned len;
	int testno;
	int exitcode = 0;

	int fd = open(fname, O_RDONLY);
	if (fd < 0) {
		printf("Couldn't open %s: %s\n", fname, strerror(errno));
		return 1;
	}
	if (fstat(fd, &st) < 0) {
		printf("Couldn't fstat %s: %s\n", fname, strerror(errno));
		return 1;
	}
	len = st.st_size;
	string = buf = malloc(len + 1);
	if (buf == NULL) {
		printf("Couldn't allocate %u bytes\n", len + 1);
		return 1;
	}
	if (read(fd, buf, st.st_size) != (ssize_t) st.st_size) {
		printf("Couldn't read %s\n", fname);
		return 1;
	}

	close(fd);
	buf[len] = '\0';

#if defined __UCLIBC_HAS_XLOCALE__ || !defined __UCLIBC__
	setlocale(LC_ALL, "de_DE.UTF-8");
#endif

	for (testno = 0; testno < 2; ++testno) {
		int i;
		for (i = 0; i < sizeof(pat) / sizeof(pat[0]); ++i) {
			struct timeval start, stop;
			regex_t rbuf;
			int err;

			printf("test %d pattern %d '%s'\n", testno, i, pat[i]);
			gettimeofday(&start, NULL);

			err = regcomp(&rbuf, pat[i],
				REG_EXTENDED | (testno ? REG_NOSUB : 0));
			if (err != 0) {
				char errstr[300];
				regerror(err, &rbuf, errstr, sizeof(errstr));
				puts(errstr);
				exitcode = 1;
				goto contin1;
			}

			regmatch_t pmatch[71];
			err = regexec(&rbuf, string, 71, pmatch, 0);
			if (err == REG_NOMATCH) {
				puts("regexec failed");
				exitcode = 1;
				goto contin1;
			}

			if (testno == 0) {
				if (pmatch[0].rm_eo != pmatch[0].rm_so + 13
				 || pmatch[0].rm_eo > len
				 || pmatch[0].rm_so < len - 100
				 || strncmp(string + pmatch[0].rm_so,
					" ChangeLog.13 for earlier changes",
					sizeof " ChangeLog.13 for earlier changes" - 1
				    ) != 0
				) {
					puts("regexec without REG_NOSUB did not find the correct match");
					exitcode = 1;
					goto contin1;
				}

				if (i > 0) {
					int j, k, l;
					for (j = 0, l = 1; j < 7; ++j) {
						for (k = 0; k < (i == 1 ? 1 : 10); ++k, ++l) {
							if (pmatch[l].rm_so != pmatch[0].rm_so + j
							|| pmatch[l].rm_eo != pmatch[l].rm_so + 1
							) {
								printf("pmatch[%d] incorrect\n", l);
								exitcode = 1;
								goto contin1;
							}
						}
					}
				}
			}

			gettimeofday(&stop, NULL);
			stop.tv_sec -= start.tv_sec;
			if (stop.tv_usec < start.tv_usec) {
				stop.tv_sec--;
				stop.tv_usec += 1000000;
			}
			stop.tv_usec -= start.tv_usec;
			printf(" %lu.%06lus\n", (unsigned long) stop.tv_sec,
						(unsigned long) stop.tv_usec);
 contin1:
			regfree(&rbuf);
		}
	}

	for (testno = 2; testno < 4; ++testno) {
		int i;
		for (i = 0; i < sizeof(pat) / sizeof(pat[0]); ++i) {
			struct timeval start, stop;
			struct re_pattern_buffer rpbuf;
			struct re_registers regs;
			const char *s;
			int match;

			printf("test %d pattern %d '%s'\n", testno, i, pat[i]);
			gettimeofday(&start, NULL);

			re_set_syntax(RE_SYNTAX_POSIX_EGREP
				| (testno == 3 ? RE_NO_SUB : 0));
			memset(&rpbuf, 0, sizeof(rpbuf));
			s = re_compile_pattern(pat[i], strlen(pat[i]), &rpbuf);
			if (s != NULL) {
				printf("%s\n", s);
				exitcode = 1;
				goto contin2;
			}

			memset(&regs, 0, sizeof(regs));
			match = re_search(&rpbuf, string, len, 0, len, &regs);
			if (match < 0) {
				printf("re_search failed (err:%d)\n", match);
				exitcode = 1;
				goto contin2;
			}
			if (match + 13 > len) {
				printf("re_search: match+13 > len (%d > %d)\n", match + 13, len);
				exitcode = 1;
				goto contin2;
			}
			if (match < len - 100) {
				printf("re_search: match < len-100 (%d < %d)\n", match, len - 100);
				exitcode = 1;
				goto contin2;
			}
			if (strncmp(string + match, " ChangeLog.13 for earlier changes",
				sizeof(" ChangeLog.13 for earlier changes") - 1
			    ) != 0
			) {
				printf("re_search did not find the correct match"
					"(found '%s' instead)\n", string + match);
				exitcode = 1;
				goto contin2;
			}

			if (testno == 2) {
				int expected = 72;
				if (i == 0)
					expected = 2;
				if (i == 1)
					expected = 9;
				if (regs.num_regs != expected) {
					printf("incorrect num_regs %d, expected %d\n", regs.num_regs, expected);
					exitcode = 1;
					goto contin2;
				}
				if (regs.start[0] != match || regs.end[0] != match + 13) {
					printf("incorrect regs.{start,end}[0] = { %d, %d },"
						" expected { %d, %d }\n",
						regs.start[0], regs.end[0],
						match, match + 13
					);
					exitcode = 1;
					goto contin2;
				}
				if (regs.start[regs.num_regs - 1] != -1
				 || regs.end[regs.num_regs - 1] != -1
				) {
					printf("incorrect regs.{start,end}[num_regs - 1] = { %d, %d },"
						" expected { -1, -1 }\n",
						regs.start[regs.num_regs - 1], regs.end[regs.num_regs - 1]
					);
					exitcode = 1;
					goto contin2;
				}

				if (i > 0) {
					int j, k, l;
					for (j = 0, l = 1; j < 7; ++j) {
						for (k = 0; k < (i == 1 ? 1 : 10); ++k, ++l) {
							if (regs.start[l] != match + j
							 || regs.end[l] != match + j + 1
							) {
								printf("incorrect regs.{start,end}[%d] = { %d, %d },"
									" expected { %d, %d }\n",
									l,
									regs.start[l], regs.end[l],
									match + j, match + j + 1
								);
								exitcode = 1;
								goto contin2;
							}
						}
					}
				}
			}

			gettimeofday(&stop, NULL);
			stop.tv_sec -= start.tv_sec;
			if (stop.tv_usec < start.tv_usec) {
				stop.tv_sec--;
				stop.tv_usec += 1000000;
			}
			stop.tv_usec -= start.tv_usec;
			printf(" %lu.%06lus\n", (unsigned long) stop.tv_sec,
						(unsigned long) stop.tv_usec);
 contin2:
			regfree(&rpbuf);
		}
	}
	return exitcode;
}