aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-05-21 18:48:54 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-05-21 19:01:37 +0300
commite79736d884ea11e64a727c51d92358d6731fb479 (patch)
treeb97ed03ecadc7c9dc7867dacaeb6ce05375310a1
parentb152cee910c15fd75e10d7cbd8afe35d079b2c70 (diff)
downloadydb-e79736d884ea11e64a727c51d92358d6731fb479.tar.gz
Remove more of unused gnulib sources from contrib/tools/bison
6f612070e58cd7e6c16b0d090a809077b0a454ff
-rw-r--r--contrib/tools/bison/lib/gettimeofday.c154
-rw-r--r--contrib/tools/bison/lib/memchr2.c169
-rw-r--r--contrib/tools/bison/lib/memchr2.h32
-rw-r--r--contrib/tools/bison/lib/realloc.c79
-rw-r--r--contrib/tools/bison/lib/regcomp.c3922
-rw-r--r--contrib/tools/bison/lib/regex.c81
-rw-r--r--contrib/tools/bison/lib/regex.h667
-rw-r--r--contrib/tools/bison/lib/regex_internal.c1741
-rw-r--r--contrib/tools/bison/lib/regex_internal.h909
-rw-r--r--contrib/tools/bison/lib/regexec.c4410
-rw-r--r--contrib/tools/bison/lib/spawn_int.h62
-rw-r--r--contrib/tools/bison/lib/spawni.c374
-rw-r--r--contrib/tools/bison/lib/spawnp.c33
-rw-r--r--contrib/tools/bison/lib/tmpdir.c159
-rw-r--r--contrib/tools/bison/lib/tmpdir.h26
-rw-r--r--contrib/tools/bison/lib/verror.c77
-rw-r--r--contrib/tools/bison/lib/verror.h54
-rw-r--r--contrib/tools/bison/lib/ya.make8
18 files changed, 0 insertions, 12957 deletions
diff --git a/contrib/tools/bison/lib/gettimeofday.c b/contrib/tools/bison/lib/gettimeofday.c
deleted file mode 100644
index ad65c6da8b..0000000000
--- a/contrib/tools/bison/lib/gettimeofday.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* Provide gettimeofday for systems that don't have it or for which it's broken.
-
- Copyright (C) 2001-2003, 2005-2007, 2009-2013 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-/* written by Jim Meyering */
-
-#include <config.h>
-
-/* Specification. */
-#include <sys/time.h>
-
-#include <time.h>
-
-#if HAVE_SYS_TIMEB_H
-# include <sys/timeb.h>
-#endif
-
-#if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME
-
-/* Work around the bug in some systems whereby gettimeofday clobbers
- the static buffer that localtime uses for its return value. The
- gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has
- this problem. The tzset replacement is necessary for at least
- Solaris 2.5, 2.5.1, and 2.6. */
-
-static struct tm tm_zero_buffer;
-static struct tm *localtime_buffer_addr = &tm_zero_buffer;
-
-# undef localtime
-extern struct tm *localtime (time_t const *);
-
-# undef gmtime
-extern struct tm *gmtime (time_t const *);
-
-/* This is a wrapper for localtime. It is used only on systems for which
- gettimeofday clobbers the static buffer used for localtime's result.
-
- On the first call, record the address of the static buffer that
- localtime uses for its result. */
-
-struct tm *
-rpl_localtime (time_t const *timep)
-{
- struct tm *tm = localtime (timep);
-
- if (localtime_buffer_addr == &tm_zero_buffer)
- localtime_buffer_addr = tm;
-
- return tm;
-}
-
-/* Same as above, since gmtime and localtime use the same buffer. */
-struct tm *
-rpl_gmtime (time_t const *timep)
-{
- struct tm *tm = gmtime (timep);
-
- if (localtime_buffer_addr == &tm_zero_buffer)
- localtime_buffer_addr = tm;
-
- return tm;
-}
-
-#endif /* GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME */
-
-#if TZSET_CLOBBERS_LOCALTIME
-
-# undef tzset
-extern void tzset (void);
-
-/* This is a wrapper for tzset, for systems on which tzset may clobber
- the static buffer used for localtime's result. */
-void
-rpl_tzset (void)
-{
- /* Save and restore the contents of the buffer used for localtime's
- result around the call to tzset. */
- struct tm save = *localtime_buffer_addr;
- tzset ();
- *localtime_buffer_addr = save;
-}
-#endif
-
-/* This is a wrapper for gettimeofday. It is used only on systems
- that lack this function, or whose implementation of this function
- causes problems. */
-
-int
-gettimeofday (struct timeval *restrict tv, void *restrict tz)
-{
-#undef gettimeofday
-#if HAVE_GETTIMEOFDAY
-# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
- /* Save and restore the contents of the buffer used for localtime's
- result around the call to gettimeofday. */
- struct tm save = *localtime_buffer_addr;
-# endif
-
-# if defined timeval /* 'struct timeval' overridden by gnulib? */
-# undef timeval
- struct timeval otv;
- int result = gettimeofday (&otv, (struct timezone *) tz);
- if (result == 0)
- {
- tv->tv_sec = otv.tv_sec;
- tv->tv_usec = otv.tv_usec;
- }
-# else
- int result = gettimeofday (tv, (struct timezone *) tz);
-# endif
-
-# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
- *localtime_buffer_addr = save;
-# endif
-
- return result;
-
-#else
-
-# if HAVE__FTIME
-
- struct _timeb timebuf;
- _ftime (&timebuf);
- tv->tv_sec = timebuf.time;
- tv->tv_usec = timebuf.millitm * 1000;
-
-# else
-
-# if !defined OK_TO_USE_1S_CLOCK
-# error "Only 1-second nominal clock resolution found. Is that intended?" \
- "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
-# endif
- tv->tv_sec = time (NULL);
- tv->tv_usec = 0;
-
-# endif
-
- return 0;
-
-#endif
-}
diff --git a/contrib/tools/bison/lib/memchr2.c b/contrib/tools/bison/lib/memchr2.c
deleted file mode 100644
index 8b105b7f27..0000000000
--- a/contrib/tools/bison/lib/memchr2.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2013
- Free Software Foundation, Inc.
-
- Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
- with help from Dan Sahlin (dan@sics.se) and
- commentary by Jim Blandy (jimb@ai.mit.edu);
- adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
- and implemented in glibc by Roland McGrath (roland@ai.mit.edu).
- Extension to memchr2 implemented by Eric Blake (ebb9@byu.net).
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 3 of the License, or any
-later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "memchr2.h"
-
-#include <limits.h>
-#include <stdint.h>
-#include <string.h>
-
-/* Return the first address of either C1 or C2 (treated as unsigned
- char) that occurs within N bytes of the memory region S. If
- neither byte appears, return NULL. */
-void *
-memchr2 (void const *s, int c1_in, int c2_in, size_t n)
-{
- /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
- long instead of a 64-bit uintmax_t tends to give better
- performance. On 64-bit hardware, unsigned long is generally 64
- bits already. Change this typedef to experiment with
- performance. */
- typedef unsigned long int longword;
-
- const unsigned char *char_ptr;
- void const *void_ptr;
- const longword *longword_ptr;
- longword repeated_one;
- longword repeated_c1;
- longword repeated_c2;
- unsigned char c1;
- unsigned char c2;
-
- c1 = (unsigned char) c1_in;
- c2 = (unsigned char) c2_in;
-
- if (c1 == c2)
- return memchr (s, c1, n);
-
- /* Handle the first few bytes by reading one byte at a time.
- Do this until VOID_PTR is aligned on a longword boundary. */
- for (void_ptr = s;
- n > 0 && (uintptr_t) void_ptr % sizeof (longword) != 0;
- --n)
- {
- char_ptr = void_ptr;
- if (*char_ptr == c1 || *char_ptr == c2)
- return (void *) void_ptr;
- void_ptr = char_ptr + 1;
- }
-
- longword_ptr = void_ptr;
-
- /* All these elucidatory comments refer to 4-byte longwords,
- but the theory applies equally well to any size longwords. */
-
- /* Compute auxiliary longword values:
- repeated_one is a value which has a 1 in every byte.
- repeated_c1 has c1 in every byte.
- repeated_c2 has c2 in every byte. */
- repeated_one = 0x01010101;
- repeated_c1 = c1 | (c1 << 8);
- repeated_c2 = c2 | (c2 << 8);
- repeated_c1 |= repeated_c1 << 16;
- repeated_c2 |= repeated_c2 << 16;
- if (0xffffffffU < (longword) -1)
- {
- repeated_one |= repeated_one << 31 << 1;
- repeated_c1 |= repeated_c1 << 31 << 1;
- repeated_c2 |= repeated_c2 << 31 << 1;
- if (8 < sizeof (longword))
- {
- size_t i;
-
- for (i = 64; i < sizeof (longword) * 8; i *= 2)
- {
- repeated_one |= repeated_one << i;
- repeated_c1 |= repeated_c1 << i;
- repeated_c2 |= repeated_c2 << i;
- }
- }
- }
-
- /* Instead of the traditional loop which tests each byte, we will test a
- longword at a time. The tricky part is testing if *any of the four*
- bytes in the longword in question are equal to c1 or c2. We first use
- an xor with repeated_c1 and repeated_c2, respectively. This reduces
- the task to testing whether *any of the four* bytes in longword1 or
- longword2 is zero.
-
- Let's consider longword1. We compute tmp1 =
- ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
- That is, we perform the following operations:
- 1. Subtract repeated_one.
- 2. & ~longword1.
- 3. & a mask consisting of 0x80 in every byte.
- Consider what happens in each byte:
- - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
- and step 3 transforms it into 0x80. A carry can also be propagated
- to more significant bytes.
- - If a byte of longword1 is nonzero, let its lowest 1 bit be at
- position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
- the byte ends in a single bit of value 0 and k bits of value 1.
- After step 2, the result is just k bits of value 1: 2^k - 1. After
- step 3, the result is 0. And no carry is produced.
- So, if longword1 has only non-zero bytes, tmp1 is zero.
- Whereas if longword1 has a zero byte, call j the position of the least
- significant zero byte. Then the result has a zero at positions 0, ...,
- j-1 and a 0x80 at position j. We cannot predict the result at the more
- significant bytes (positions j+1..3), but it does not matter since we
- already have a non-zero bit at position 8*j+7.
-
- Similarly, we compute tmp2 =
- ((longword2 - repeated_one) & ~longword2) & (repeated_one << 7).
-
- The test whether any byte in longword1 or longword2 is zero is equivalent
- to testing whether tmp1 is nonzero or tmp2 is nonzero. We can combine
- this into a single test, whether (tmp1 | tmp2) is nonzero. */
-
- while (n >= sizeof (longword))
- {
- longword longword1 = *longword_ptr ^ repeated_c1;
- longword longword2 = *longword_ptr ^ repeated_c2;
-
- if (((((longword1 - repeated_one) & ~longword1)
- | ((longword2 - repeated_one) & ~longword2))
- & (repeated_one << 7)) != 0)
- break;
- longword_ptr++;
- n -= sizeof (longword);
- }
-
- char_ptr = (const unsigned char *) longword_ptr;
-
- /* At this point, we know that either n < sizeof (longword), or one of the
- sizeof (longword) bytes starting at char_ptr is == c1 or == c2. On
- little-endian machines, we could determine the first such byte without
- any further memory accesses, just by looking at the (tmp1 | tmp2) result
- from the last loop iteration. But this does not work on big-endian
- machines. Choose code that works in both cases. */
-
- for (; n > 0; --n, ++char_ptr)
- {
- if (*char_ptr == c1 || *char_ptr == c2)
- return (void *) char_ptr;
- }
-
- return NULL;
-}
diff --git a/contrib/tools/bison/lib/memchr2.h b/contrib/tools/bison/lib/memchr2.h
deleted file mode 100644
index cc04889f12..0000000000
--- a/contrib/tools/bison/lib/memchr2.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Scan memory for the first of two bytes.
- Copyright (C) 2008-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Return the first address of either C1 or C2 (treated as unsigned
- char) that occurs within N bytes of the memory region S. If
- neither byte appears, return NULL. */
-
-extern void *memchr2 (void const *s, int c1, int c2, size_t n)
- _GL_ATTRIBUTE_PURE;
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/contrib/tools/bison/lib/realloc.c b/contrib/tools/bison/lib/realloc.c
deleted file mode 100644
index b51010a621..0000000000
--- a/contrib/tools/bison/lib/realloc.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* realloc() function that is glibc compatible.
-
- Copyright (C) 1997, 2003-2004, 2006-2007, 2009-2013 Free Software
- Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* written by Jim Meyering and Bruno Haible */
-
-#define _GL_USE_STDLIB_ALLOC 1
-#include <config.h>
-
-/* Only the AC_FUNC_REALLOC macro defines 'realloc' already in config.h. */
-#ifdef realloc
-# define NEED_REALLOC_GNU 1
-/* Whereas the gnulib module 'realloc-gnu' defines HAVE_REALLOC_GNU. */
-#elif GNULIB_REALLOC_GNU && !HAVE_REALLOC_GNU
-# define NEED_REALLOC_GNU 1
-#endif
-
-/* Infer the properties of the system's malloc function.
- The gnulib module 'malloc-gnu' defines HAVE_MALLOC_GNU. */
-#if GNULIB_MALLOC_GNU && HAVE_MALLOC_GNU
-# define SYSTEM_MALLOC_GLIBC_COMPATIBLE 1
-#endif
-
-#include <stdlib.h>
-
-#include <errno.h>
-
-/* Change the size of an allocated block of memory P to N bytes,
- with error checking. If N is zero, change it to 1. If P is NULL,
- use malloc. */
-
-void *
-rpl_realloc (void *p, size_t n)
-{
- void *result;
-
-#if NEED_REALLOC_GNU
- if (n == 0)
- {
- n = 1;
-
- /* In theory realloc might fail, so don't rely on it to free. */
- free (p);
- p = NULL;
- }
-#endif
-
- if (p == NULL)
- {
-#if GNULIB_REALLOC_GNU && !NEED_REALLOC_GNU && !SYSTEM_MALLOC_GLIBC_COMPATIBLE
- if (n == 0)
- n = 1;
-#endif
- result = malloc (n);
- }
- else
- result = realloc (p, n);
-
-#if !HAVE_REALLOC_POSIX
- if (result == NULL)
- errno = ENOMEM;
-#endif
-
- return result;
-}
diff --git a/contrib/tools/bison/lib/regcomp.c b/contrib/tools/bison/lib/regcomp.c
deleted file mode 100644
index f0b2e52216..0000000000
--- a/contrib/tools/bison/lib/regcomp.c
+++ /dev/null
@@ -1,3922 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
- size_t length, reg_syntax_t syntax);
-static void re_compile_fastmap_iter (regex_t *bufp,
- const re_dfastate_t *init_state,
- char *fastmap);
-static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
-#ifdef RE_ENABLE_I18N
-static void free_charset (re_charset_t *cset);
-#endif /* RE_ENABLE_I18N */
-static void free_workarea_compile (regex_t *preg);
-static reg_errcode_t create_initial_state (re_dfa_t *dfa);
-#ifdef RE_ENABLE_I18N
-static void optimize_utf8 (re_dfa_t *dfa);
-#endif
-static reg_errcode_t analyze (regex_t *preg);
-static reg_errcode_t preorder (bin_tree_t *root,
- reg_errcode_t (fn (void *, bin_tree_t *)),
- void *extra);
-static reg_errcode_t postorder (bin_tree_t *root,
- reg_errcode_t (fn (void *, bin_tree_t *)),
- void *extra);
-static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
-static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
-static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
- bin_tree_t *node);
-static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
-static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
-static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
-static Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint);
-static Idx search_duplicated_node (const re_dfa_t *dfa, Idx org_node,
- unsigned int constraint);
-static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
-static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
- Idx node, bool root);
-static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
-static Idx fetch_number (re_string_t *input, re_token_t *token,
- reg_syntax_t syntax);
-static int peek_token (re_token_t *token, re_string_t *input,
- reg_syntax_t syntax) internal_function;
-static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
- reg_syntax_t syntax, reg_errcode_t *err);
-static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
- re_token_t *token, reg_syntax_t syntax,
- Idx nest, reg_errcode_t *err);
-static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
- re_token_t *token, reg_syntax_t syntax,
- Idx nest, reg_errcode_t *err);
-static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
- re_token_t *token, reg_syntax_t syntax,
- Idx nest, reg_errcode_t *err);
-static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
- re_token_t *token, reg_syntax_t syntax,
- Idx nest, reg_errcode_t *err);
-static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
- re_dfa_t *dfa, re_token_t *token,
- reg_syntax_t syntax, reg_errcode_t *err);
-static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
- re_token_t *token, reg_syntax_t syntax,
- reg_errcode_t *err);
-static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
- re_string_t *regexp,
- re_token_t *token, int token_len,
- re_dfa_t *dfa,
- reg_syntax_t syntax,
- bool accept_hyphen);
-static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
- re_string_t *regexp,
- re_token_t *token);
-#ifdef RE_ENABLE_I18N
-static reg_errcode_t build_equiv_class (bitset_t sbcset,
- re_charset_t *mbcset,
- Idx *equiv_class_alloc,
- const unsigned char *name);
-static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
- bitset_t sbcset,
- re_charset_t *mbcset,
- Idx *char_class_alloc,
- const char *class_name,
- reg_syntax_t syntax);
-#else /* not RE_ENABLE_I18N */
-static reg_errcode_t build_equiv_class (bitset_t sbcset,
- const unsigned char *name);
-static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
- bitset_t sbcset,
- const char *class_name,
- reg_syntax_t syntax);
-#endif /* not RE_ENABLE_I18N */
-static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
- RE_TRANSLATE_TYPE trans,
- const char *class_name,
- const char *extra,
- bool non_match, reg_errcode_t *err);
-static bin_tree_t *create_tree (re_dfa_t *dfa,
- bin_tree_t *left, bin_tree_t *right,
- re_token_type_t type);
-static bin_tree_t *create_token_tree (re_dfa_t *dfa,
- bin_tree_t *left, bin_tree_t *right,
- const re_token_t *token);
-static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
-static void free_token (re_token_t *node);
-static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
-static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
-
-/* This table gives an error message for each of the error codes listed
- in regex.h. Obviously the order here has to be same as there.
- POSIX doesn't require that we do anything for REG_NOERROR,
- but why not be nice? */
-
-static const char __re_error_msgid[] =
- {
-#define REG_NOERROR_IDX 0
- gettext_noop ("Success") /* REG_NOERROR */
- "\0"
-#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
- gettext_noop ("No match") /* REG_NOMATCH */
- "\0"
-#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
- gettext_noop ("Invalid regular expression") /* REG_BADPAT */
- "\0"
-#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
- gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
- "\0"
-#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
- gettext_noop ("Invalid character class name") /* REG_ECTYPE */
- "\0"
-#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
- gettext_noop ("Trailing backslash") /* REG_EESCAPE */
- "\0"
-#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
- gettext_noop ("Invalid back reference") /* REG_ESUBREG */
- "\0"
-#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
- gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
- "\0"
-#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
- gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
- "\0"
-#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
- gettext_noop ("Unmatched \\{") /* REG_EBRACE */
- "\0"
-#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
- gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
- "\0"
-#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
- gettext_noop ("Invalid range end") /* REG_ERANGE */
- "\0"
-#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
- gettext_noop ("Memory exhausted") /* REG_ESPACE */
- "\0"
-#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
- gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
- "\0"
-#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
- gettext_noop ("Premature end of regular expression") /* REG_EEND */
- "\0"
-#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
- gettext_noop ("Regular expression too big") /* REG_ESIZE */
- "\0"
-#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
- gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
- };
-
-static const size_t __re_error_msgid_idx[] =
- {
- REG_NOERROR_IDX,
- REG_NOMATCH_IDX,
- REG_BADPAT_IDX,
- REG_ECOLLATE_IDX,
- REG_ECTYPE_IDX,
- REG_EESCAPE_IDX,
- REG_ESUBREG_IDX,
- REG_EBRACK_IDX,
- REG_EPAREN_IDX,
- REG_EBRACE_IDX,
- REG_BADBR_IDX,
- REG_ERANGE_IDX,
- REG_ESPACE_IDX,
- REG_BADRPT_IDX,
- REG_EEND_IDX,
- REG_ESIZE_IDX,
- REG_ERPAREN_IDX
- };
-
-/* Entry points for GNU code. */
-
-/* re_compile_pattern is the GNU regular expression compiler: it
- compiles PATTERN (of length LENGTH) and puts the result in BUFP.
- Returns 0 if the pattern was valid, otherwise an error string.
-
- Assumes the 'allocated' (and perhaps 'buffer') and 'translate' fields
- are set in BUFP on entry. */
-
-#ifdef _LIBC
-const char *
-re_compile_pattern (pattern, length, bufp)
- const char *pattern;
- size_t length;
- struct re_pattern_buffer *bufp;
-#else /* size_t might promote */
-const char *
-re_compile_pattern (const char *pattern, size_t length,
- struct re_pattern_buffer *bufp)
-#endif
-{
- reg_errcode_t ret;
-
- /* And GNU code determines whether or not to get register information
- by passing null for the REGS argument to re_match, etc., not by
- setting no_sub, unless RE_NO_SUB is set. */
- bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
-
- /* Match anchors at newline. */
- bufp->newline_anchor = 1;
-
- ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
-
- if (!ret)
- return NULL;
- return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
-}
-#ifdef _LIBC
-weak_alias (__re_compile_pattern, re_compile_pattern)
-#endif
-
-/* Set by 're_set_syntax' to the current regexp syntax to recognize. Can
- also be assigned to arbitrarily: each pattern buffer stores its own
- syntax, so it can be changed between regex compilations. */
-/* This has no initializer because initialized variables in Emacs
- become read-only after dumping. */
-reg_syntax_t re_syntax_options;
-
-
-/* Specify the precise syntax of regexps for compilation. This provides
- for compatibility for various utilities which historically have
- different, incompatible syntaxes.
-
- The argument SYNTAX is a bit mask comprised of the various bits
- defined in regex.h. We return the old syntax. */
-
-reg_syntax_t
-re_set_syntax (syntax)
- reg_syntax_t syntax;
-{
- reg_syntax_t ret = re_syntax_options;
-
- re_syntax_options = syntax;
- return ret;
-}
-#ifdef _LIBC
-weak_alias (__re_set_syntax, re_set_syntax)
-#endif
-
-int
-re_compile_fastmap (bufp)
- struct re_pattern_buffer *bufp;
-{
- re_dfa_t *dfa = bufp->buffer;
- char *fastmap = bufp->fastmap;
-
- memset (fastmap, '\0', sizeof (char) * SBC_MAX);
- re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
- if (dfa->init_state != dfa->init_state_word)
- re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
- if (dfa->init_state != dfa->init_state_nl)
- re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
- if (dfa->init_state != dfa->init_state_begbuf)
- re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
- bufp->fastmap_accurate = 1;
- return 0;
-}
-#ifdef _LIBC
-weak_alias (__re_compile_fastmap, re_compile_fastmap)
-#endif
-
-static inline void
-__attribute__ ((always_inline))
-re_set_fastmap (char *fastmap, bool icase, int ch)
-{
- fastmap[ch] = 1;
- if (icase)
- fastmap[tolower (ch)] = 1;
-}
-
-/* Helper function for re_compile_fastmap.
- Compile fastmap for the initial_state INIT_STATE. */
-
-static void
-re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
- char *fastmap)
-{
- re_dfa_t *dfa = bufp->buffer;
- Idx node_cnt;
- bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
- for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
- {
- Idx node = init_state->nodes.elems[node_cnt];
- re_token_type_t type = dfa->nodes[node].type;
-
- if (type == CHARACTER)
- {
- re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
-#ifdef RE_ENABLE_I18N
- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
- {
- unsigned char buf[MB_LEN_MAX];
- unsigned char *p;
- wchar_t wc;
- mbstate_t state;
-
- p = buf;
- *p++ = dfa->nodes[node].opr.c;
- while (++node < dfa->nodes_len
- && dfa->nodes[node].type == CHARACTER
- && dfa->nodes[node].mb_partial)
- *p++ = dfa->nodes[node].opr.c;
- memset (&state, '\0', sizeof (state));
- if (__mbrtowc (&wc, (const char *) buf, p - buf,
- &state) == p - buf
- && (__wcrtomb ((char *) buf, towlower (wc), &state)
- != (size_t) -1))
- re_set_fastmap (fastmap, false, buf[0]);
- }
-#endif
- }
- else if (type == SIMPLE_BRACKET)
- {
- int i, ch;
- for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
- {
- int j;
- bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
- for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
- if (w & ((bitset_word_t) 1 << j))
- re_set_fastmap (fastmap, icase, ch);
- }
- }
-#ifdef RE_ENABLE_I18N
- else if (type == COMPLEX_BRACKET)
- {
- re_charset_t *cset = dfa->nodes[node].opr.mbcset;
- Idx i;
-
-# ifdef _LIBC
- /* See if we have to try all bytes which start multiple collation
- elements.
- e.g. In da_DK, we want to catch 'a' since "aa" is a valid
- collation element, and don't catch 'b' since 'b' is
- the only collation element which starts from 'b' (and
- it is caught by SIMPLE_BRACKET). */
- if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0
- && (cset->ncoll_syms || cset->nranges))
- {
- const int32_t *table = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
- for (i = 0; i < SBC_MAX; ++i)
- if (table[i] < 0)
- re_set_fastmap (fastmap, icase, i);
- }
-# endif /* _LIBC */
-
- /* See if we have to start the match at all multibyte characters,
- i.e. where we would not find an invalid sequence. This only
- applies to multibyte character sets; for single byte character
- sets, the SIMPLE_BRACKET again suffices. */
- if (dfa->mb_cur_max > 1
- && (cset->nchar_classes || cset->non_match || cset->nranges
-# ifdef _LIBC
- || cset->nequiv_classes
-# endif /* _LIBC */
- ))
- {
- unsigned char c = 0;
- do
- {
- mbstate_t mbs;
- memset (&mbs, 0, sizeof (mbs));
- if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2)
- re_set_fastmap (fastmap, false, (int) c);
- }
- while (++c != 0);
- }
-
- else
- {
- /* ... Else catch all bytes which can start the mbchars. */
- for (i = 0; i < cset->nmbchars; ++i)
- {
- char buf[256];
- mbstate_t state;
- memset (&state, '\0', sizeof (state));
- if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
- re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
- {
- if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
- != (size_t) -1)
- re_set_fastmap (fastmap, false, *(unsigned char *) buf);
- }
- }
- }
- }
-#endif /* RE_ENABLE_I18N */
- else if (type == OP_PERIOD
-#ifdef RE_ENABLE_I18N
- || type == OP_UTF8_PERIOD
-#endif /* RE_ENABLE_I18N */
- || type == END_OF_RE)
- {
- memset (fastmap, '\1', sizeof (char) * SBC_MAX);
- if (type == END_OF_RE)
- bufp->can_be_null = 1;
- return;
- }
- }
-}
-
-/* Entry point for POSIX code. */
-/* regcomp takes a regular expression as a string and compiles it.
-
- PREG is a regex_t *. We do not expect any fields to be initialized,
- since POSIX says we shouldn't. Thus, we set
-
- 'buffer' to the compiled pattern;
- 'used' to the length of the compiled pattern;
- 'syntax' to RE_SYNTAX_POSIX_EXTENDED if the
- REG_EXTENDED bit in CFLAGS is set; otherwise, to
- RE_SYNTAX_POSIX_BASIC;
- 'newline_anchor' to REG_NEWLINE being set in CFLAGS;
- 'fastmap' to an allocated space for the fastmap;
- 'fastmap_accurate' to zero;
- 're_nsub' to the number of subexpressions in PATTERN.
-
- PATTERN is the address of the pattern string.
-
- CFLAGS is a series of bits which affect compilation.
-
- If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
- use POSIX basic syntax.
-
- If REG_NEWLINE is set, then . and [^...] don't match newline.
- Also, regexec will try a match beginning after every newline.
-
- If REG_ICASE is set, then we considers upper- and lowercase
- versions of letters to be equivalent when matching.
-
- If REG_NOSUB is set, then when PREG is passed to regexec, that
- routine will report only success or failure, and nothing about the
- registers.
-
- It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
- the return codes and their meanings.) */
-
-int
-regcomp (preg, pattern, cflags)
- regex_t *_Restrict_ preg;
- const char *_Restrict_ pattern;
- int cflags;
-{
- reg_errcode_t ret;
- reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
- : RE_SYNTAX_POSIX_BASIC);
-
- preg->buffer = NULL;
- preg->allocated = 0;
- preg->used = 0;
-
- /* Try to allocate space for the fastmap. */
- preg->fastmap = re_malloc (char, SBC_MAX);
- if (BE (preg->fastmap == NULL, 0))
- return REG_ESPACE;
-
- syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
-
- /* If REG_NEWLINE is set, newlines are treated differently. */
- if (cflags & REG_NEWLINE)
- { /* REG_NEWLINE implies neither . nor [^...] match newline. */
- syntax &= ~RE_DOT_NEWLINE;
- syntax |= RE_HAT_LISTS_NOT_NEWLINE;
- /* It also changes the matching behavior. */
- preg->newline_anchor = 1;
- }
- else
- preg->newline_anchor = 0;
- preg->no_sub = !!(cflags & REG_NOSUB);
- preg->translate = NULL;
-
- ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
-
- /* POSIX doesn't distinguish between an unmatched open-group and an
- unmatched close-group: both are REG_EPAREN. */
- if (ret == REG_ERPAREN)
- ret = REG_EPAREN;
-
- /* We have already checked preg->fastmap != NULL. */
- if (BE (ret == REG_NOERROR, 1))
- /* Compute the fastmap now, since regexec cannot modify the pattern
- buffer. This function never fails in this implementation. */
- (void) re_compile_fastmap (preg);
- else
- {
- /* Some error occurred while compiling the expression. */
- re_free (preg->fastmap);
- preg->fastmap = NULL;
- }
-
- return (int) ret;
-}
-#ifdef _LIBC
-weak_alias (__regcomp, regcomp)
-#endif
-
-/* Returns a message corresponding to an error code, ERRCODE, returned
- from either regcomp or regexec. We don't use PREG here. */
-
-#ifdef _LIBC
-size_t
-regerror (errcode, preg, errbuf, errbuf_size)
- int errcode;
- const regex_t *_Restrict_ preg;
- char *_Restrict_ errbuf;
- size_t errbuf_size;
-#else /* size_t might promote */
-size_t
-regerror (int errcode, const regex_t *_Restrict_ preg,
- char *_Restrict_ errbuf, size_t errbuf_size)
-#endif
-{
- const char *msg;
- size_t msg_size;
-
- if (BE (errcode < 0
- || errcode >= (int) (sizeof (__re_error_msgid_idx)
- / sizeof (__re_error_msgid_idx[0])), 0))
- /* Only error codes returned by the rest of the code should be passed
- to this routine. If we are given anything else, or if other regex
- code generates an invalid error code, then the program has a bug.
- Dump core so we can fix it. */
- abort ();
-
- msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
-
- msg_size = strlen (msg) + 1; /* Includes the null. */
-
- if (BE (errbuf_size != 0, 1))
- {
- size_t cpy_size = msg_size;
- if (BE (msg_size > errbuf_size, 0))
- {
- cpy_size = errbuf_size - 1;
- errbuf[cpy_size] = '\0';
- }
- memcpy (errbuf, msg, cpy_size);
- }
-
- return msg_size;
-}
-#ifdef _LIBC
-weak_alias (__regerror, regerror)
-#endif
-
-
-#ifdef RE_ENABLE_I18N
-/* This static array is used for the map to single-byte characters when
- UTF-8 is used. Otherwise we would allocate memory just to initialize
- it the same all the time. UTF-8 is the preferred encoding so this is
- a worthwhile optimization. */
-static const bitset_t utf8_sb_map =
-{
- /* Set the first 128 bits. */
-# if defined __GNUC__ && !defined __STRICT_ANSI__
- [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
-# else
-# if 4 * BITSET_WORD_BITS < ASCII_CHARS
-# error "bitset_word_t is narrower than 32 bits"
-# elif 3 * BITSET_WORD_BITS < ASCII_CHARS
- BITSET_WORD_MAX, BITSET_WORD_MAX, BITSET_WORD_MAX,
-# elif 2 * BITSET_WORD_BITS < ASCII_CHARS
- BITSET_WORD_MAX, BITSET_WORD_MAX,
-# elif 1 * BITSET_WORD_BITS < ASCII_CHARS
- BITSET_WORD_MAX,
-# endif
- (BITSET_WORD_MAX
- >> (SBC_MAX % BITSET_WORD_BITS == 0
- ? 0
- : BITSET_WORD_BITS - SBC_MAX % BITSET_WORD_BITS))
-# endif
-};
-#endif
-
-
-static void
-free_dfa_content (re_dfa_t *dfa)
-{
- Idx i, j;
-
- if (dfa->nodes)
- for (i = 0; i < dfa->nodes_len; ++i)
- free_token (dfa->nodes + i);
- re_free (dfa->nexts);
- for (i = 0; i < dfa->nodes_len; ++i)
- {
- if (dfa->eclosures != NULL)
- re_node_set_free (dfa->eclosures + i);
- if (dfa->inveclosures != NULL)
- re_node_set_free (dfa->inveclosures + i);
- if (dfa->edests != NULL)
- re_node_set_free (dfa->edests + i);
- }
- re_free (dfa->edests);
- re_free (dfa->eclosures);
- re_free (dfa->inveclosures);
- re_free (dfa->nodes);
-
- if (dfa->state_table)
- for (i = 0; i <= dfa->state_hash_mask; ++i)
- {
- struct re_state_table_entry *entry = dfa->state_table + i;
- for (j = 0; j < entry->num; ++j)
- {
- re_dfastate_t *state = entry->array[j];
- free_state (state);
- }
- re_free (entry->array);
- }
- re_free (dfa->state_table);
-#ifdef RE_ENABLE_I18N
- if (dfa->sb_char != utf8_sb_map)
- re_free (dfa->sb_char);
-#endif
- re_free (dfa->subexp_map);
-#ifdef DEBUG
- re_free (dfa->re_str);
-#endif
-
- re_free (dfa);
-}
-
-
-/* Free dynamically allocated space used by PREG. */
-
-void
-regfree (preg)
- regex_t *preg;
-{
- re_dfa_t *dfa = preg->buffer;
- if (BE (dfa != NULL, 1))
- {
- lock_fini (dfa->lock);
- free_dfa_content (dfa);
- }
- preg->buffer = NULL;
- preg->allocated = 0;
-
- re_free (preg->fastmap);
- preg->fastmap = NULL;
-
- re_free (preg->translate);
- preg->translate = NULL;
-}
-#ifdef _LIBC
-weak_alias (__regfree, regfree)
-#endif
-
-/* Entry points compatible with 4.2 BSD regex library. We don't define
- them unless specifically requested. */
-
-#if defined _REGEX_RE_COMP || defined _LIBC
-
-/* BSD has one and only one pattern buffer. */
-static struct re_pattern_buffer re_comp_buf;
-
-char *
-# ifdef _LIBC
-/* Make these definitions weak in libc, so POSIX programs can redefine
- these names if they don't use our functions, and still use
- regcomp/regexec above without link errors. */
-weak_function
-# endif
-re_comp (s)
- const char *s;
-{
- reg_errcode_t ret;
- char *fastmap;
-
- if (!s)
- {
- if (!re_comp_buf.buffer)
- return gettext ("No previous regular expression");
- return 0;
- }
-
- if (re_comp_buf.buffer)
- {
- fastmap = re_comp_buf.fastmap;
- re_comp_buf.fastmap = NULL;
- __regfree (&re_comp_buf);
- memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
- re_comp_buf.fastmap = fastmap;
- }
-
- if (re_comp_buf.fastmap == NULL)
- {
- re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
- if (re_comp_buf.fastmap == NULL)
- return (char *) gettext (__re_error_msgid
- + __re_error_msgid_idx[(int) REG_ESPACE]);
- }
-
- /* Since 're_exec' always passes NULL for the 'regs' argument, we
- don't need to initialize the pattern buffer fields which affect it. */
-
- /* Match anchors at newlines. */
- re_comp_buf.newline_anchor = 1;
-
- ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
-
- if (!ret)
- return NULL;
-
- /* Yes, we're discarding 'const' here if !HAVE_LIBINTL. */
- return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
-}
-
-#ifdef _LIBC
-libc_freeres_fn (free_mem)
-{
- __regfree (&re_comp_buf);
-}
-#endif
-
-#endif /* _REGEX_RE_COMP */
-
-/* Internal entry point.
- Compile the regular expression PATTERN, whose length is LENGTH.
- SYNTAX indicate regular expression's syntax. */
-
-static reg_errcode_t
-re_compile_internal (regex_t *preg, const char * pattern, size_t length,
- reg_syntax_t syntax)
-{
- reg_errcode_t err = REG_NOERROR;
- re_dfa_t *dfa;
- re_string_t regexp;
-
- /* Initialize the pattern buffer. */
- preg->fastmap_accurate = 0;
- preg->syntax = syntax;
- preg->not_bol = preg->not_eol = 0;
- preg->used = 0;
- preg->re_nsub = 0;
- preg->can_be_null = 0;
- preg->regs_allocated = REGS_UNALLOCATED;
-
- /* Initialize the dfa. */
- dfa = preg->buffer;
- if (BE (preg->allocated < sizeof (re_dfa_t), 0))
- {
- /* If zero allocated, but buffer is non-null, try to realloc
- enough space. This loses if buffer's address is bogus, but
- that is the user's responsibility. If ->buffer is NULL this
- is a simple allocation. */
- dfa = re_realloc (preg->buffer, re_dfa_t, 1);
- if (dfa == NULL)
- return REG_ESPACE;
- preg->allocated = sizeof (re_dfa_t);
- preg->buffer = dfa;
- }
- preg->used = sizeof (re_dfa_t);
-
- err = init_dfa (dfa, length);
- if (BE (err == REG_NOERROR && lock_init (dfa->lock) != 0, 0))
- err = REG_ESPACE;
- if (BE (err != REG_NOERROR, 0))
- {
- free_dfa_content (dfa);
- preg->buffer = NULL;
- preg->allocated = 0;
- return err;
- }
-#ifdef DEBUG
- /* Note: length+1 will not overflow since it is checked in init_dfa. */
- dfa->re_str = re_malloc (char, length + 1);
- strncpy (dfa->re_str, pattern, length + 1);
-#endif
-
- err = re_string_construct (&regexp, pattern, length, preg->translate,
- (syntax & RE_ICASE) != 0, dfa);
- if (BE (err != REG_NOERROR, 0))
- {
- re_compile_internal_free_return:
- free_workarea_compile (preg);
- re_string_destruct (&regexp);
- lock_fini (dfa->lock);
- free_dfa_content (dfa);
- preg->buffer = NULL;
- preg->allocated = 0;
- return err;
- }
-
- /* Parse the regular expression, and build a structure tree. */
- preg->re_nsub = 0;
- dfa->str_tree = parse (&regexp, preg, syntax, &err);
- if (BE (dfa->str_tree == NULL, 0))
- goto re_compile_internal_free_return;
-
- /* Analyze the tree and create the nfa. */
- err = analyze (preg);
- if (BE (err != REG_NOERROR, 0))
- goto re_compile_internal_free_return;
-
-#ifdef RE_ENABLE_I18N
- /* If possible, do searching in single byte encoding to speed things up. */
- if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
- optimize_utf8 (dfa);
-#endif
-
- /* Then create the initial state of the dfa. */
- err = create_initial_state (dfa);
-
- /* Release work areas. */
- free_workarea_compile (preg);
- re_string_destruct (&regexp);
-
- if (BE (err != REG_NOERROR, 0))
- {
- lock_fini (dfa->lock);
- free_dfa_content (dfa);
- preg->buffer = NULL;
- preg->allocated = 0;
- }
-
- return err;
-}
-
-/* Initialize DFA. We use the length of the regular expression PAT_LEN
- as the initial length of some arrays. */
-
-static reg_errcode_t
-init_dfa (re_dfa_t *dfa, size_t pat_len)
-{
- __re_size_t table_size;
-#ifndef _LIBC
- const char *codeset_name;
-#endif
-#ifdef RE_ENABLE_I18N
- size_t max_i18n_object_size = MAX (sizeof (wchar_t), sizeof (wctype_t));
-#else
- size_t max_i18n_object_size = 0;
-#endif
- size_t max_object_size =
- MAX (sizeof (struct re_state_table_entry),
- MAX (sizeof (re_token_t),
- MAX (sizeof (re_node_set),
- MAX (sizeof (regmatch_t),
- max_i18n_object_size))));
-
- memset (dfa, '\0', sizeof (re_dfa_t));
-
- /* Force allocation of str_tree_storage the first time. */
- dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
-
- /* Avoid overflows. The extra "/ 2" is for the table_size doubling
- calculation below, and for similar doubling calculations
- elsewhere. And it's <= rather than <, because some of the
- doubling calculations add 1 afterwards. */
- if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) / 2 <= pat_len, 0))
- return REG_ESPACE;
-
- dfa->nodes_alloc = pat_len + 1;
- dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
-
- /* table_size = 2 ^ ceil(log pat_len) */
- for (table_size = 1; ; table_size <<= 1)
- if (table_size > pat_len)
- break;
-
- dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
- dfa->state_hash_mask = table_size - 1;
-
- dfa->mb_cur_max = MB_CUR_MAX;
-#ifdef _LIBC
- if (dfa->mb_cur_max == 6
- && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
- dfa->is_utf8 = 1;
- dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
- != 0);
-#else
- codeset_name = nl_langinfo (CODESET);
- if ((codeset_name[0] == 'U' || codeset_name[0] == 'u')
- && (codeset_name[1] == 'T' || codeset_name[1] == 't')
- && (codeset_name[2] == 'F' || codeset_name[2] == 'f')
- && strcmp (codeset_name + 3 + (codeset_name[3] == '-'), "8") == 0)
- dfa->is_utf8 = 1;
-
- /* We check exhaustively in the loop below if this charset is a
- superset of ASCII. */
- dfa->map_notascii = 0;
-#endif
-
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- {
- if (dfa->is_utf8)
- dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
- else
- {
- int i, j, ch;
-
- dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
- if (BE (dfa->sb_char == NULL, 0))
- return REG_ESPACE;
-
- /* Set the bits corresponding to single byte chars. */
- for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
- for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
- {
- wint_t wch = __btowc (ch);
- if (wch != WEOF)
- dfa->sb_char[i] |= (bitset_word_t) 1 << j;
-# ifndef _LIBC
- if (isascii (ch) && wch != ch)
- dfa->map_notascii = 1;
-# endif
- }
- }
- }
-#endif
-
- if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
- return REG_ESPACE;
- return REG_NOERROR;
-}
-
-/* Initialize WORD_CHAR table, which indicate which character is
- "word". In this case "word" means that it is the word construction
- character used by some operators like "\<", "\>", etc. */
-
-static void
-internal_function
-init_word_char (re_dfa_t *dfa)
-{
- int i = 0;
- int j;
- int ch = 0;
- dfa->word_ops_used = 1;
- if (BE (dfa->map_notascii == 0, 1))
- {
- bitset_word_t bits0 = 0x00000000;
- bitset_word_t bits1 = 0x03ff0000;
- bitset_word_t bits2 = 0x87fffffe;
- bitset_word_t bits3 = 0x07fffffe;
- if (BITSET_WORD_BITS == 64)
- {
- dfa->word_char[0] = bits1 << 31 << 1 | bits0;
- dfa->word_char[1] = bits3 << 31 << 1 | bits2;
- i = 2;
- }
- else if (BITSET_WORD_BITS == 32)
- {
- dfa->word_char[0] = bits0;
- dfa->word_char[1] = bits1;
- dfa->word_char[2] = bits2;
- dfa->word_char[3] = bits3;
- i = 4;
- }
- else
- goto general_case;
- ch = 128;
-
- if (BE (dfa->is_utf8, 1))
- {
- memset (&dfa->word_char[i], '\0', (SBC_MAX - ch) / 8);
- return;
- }
- }
-
- general_case:
- for (; i < BITSET_WORDS; ++i)
- for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
- if (isalnum (ch) || ch == '_')
- dfa->word_char[i] |= (bitset_word_t) 1 << j;
-}
-
-/* Free the work area which are only used while compiling. */
-
-static void
-free_workarea_compile (regex_t *preg)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_storage_t *storage, *next;
- for (storage = dfa->str_tree_storage; storage; storage = next)
- {
- next = storage->next;
- re_free (storage);
- }
- dfa->str_tree_storage = NULL;
- dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
- dfa->str_tree = NULL;
- re_free (dfa->org_indices);
- dfa->org_indices = NULL;
-}
-
-/* Create initial states for all contexts. */
-
-static reg_errcode_t
-create_initial_state (re_dfa_t *dfa)
-{
- Idx first, i;
- reg_errcode_t err;
- re_node_set init_nodes;
-
- /* Initial states have the epsilon closure of the node which is
- the first node of the regular expression. */
- first = dfa->str_tree->first->node_idx;
- dfa->init_node = first;
- err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- /* The back-references which are in initial states can epsilon transit,
- since in this case all of the subexpressions can be null.
- Then we add epsilon closures of the nodes which are the next nodes of
- the back-references. */
- if (dfa->nbackref > 0)
- for (i = 0; i < init_nodes.nelem; ++i)
- {
- Idx node_idx = init_nodes.elems[i];
- re_token_type_t type = dfa->nodes[node_idx].type;
-
- Idx clexp_idx;
- if (type != OP_BACK_REF)
- continue;
- for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
- {
- re_token_t *clexp_node;
- clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
- if (clexp_node->type == OP_CLOSE_SUBEXP
- && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
- break;
- }
- if (clexp_idx == init_nodes.nelem)
- continue;
-
- if (type == OP_BACK_REF)
- {
- Idx dest_idx = dfa->edests[node_idx].elems[0];
- if (!re_node_set_contains (&init_nodes, dest_idx))
- {
- reg_errcode_t merge_err
- = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
- if (merge_err != REG_NOERROR)
- return merge_err;
- i = 0;
- }
- }
- }
-
- /* It must be the first time to invoke acquire_state. */
- dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
- /* We don't check ERR here, since the initial state must not be NULL. */
- if (BE (dfa->init_state == NULL, 0))
- return err;
- if (dfa->init_state->has_constraint)
- {
- dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
- CONTEXT_WORD);
- dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
- CONTEXT_NEWLINE);
- dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
- &init_nodes,
- CONTEXT_NEWLINE
- | CONTEXT_BEGBUF);
- if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
- || dfa->init_state_begbuf == NULL, 0))
- return err;
- }
- else
- dfa->init_state_word = dfa->init_state_nl
- = dfa->init_state_begbuf = dfa->init_state;
-
- re_node_set_free (&init_nodes);
- return REG_NOERROR;
-}
-
-#ifdef RE_ENABLE_I18N
-/* If it is possible to do searching in single byte encoding instead of UTF-8
- to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
- DFA nodes where needed. */
-
-static void
-optimize_utf8 (re_dfa_t *dfa)
-{
- Idx node;
- int i;
- bool mb_chars = false;
- bool has_period = false;
-
- for (node = 0; node < dfa->nodes_len; ++node)
- switch (dfa->nodes[node].type)
- {
- case CHARACTER:
- if (dfa->nodes[node].opr.c >= ASCII_CHARS)
- mb_chars = true;
- break;
- case ANCHOR:
- switch (dfa->nodes[node].opr.ctx_type)
- {
- case LINE_FIRST:
- case LINE_LAST:
- case BUF_FIRST:
- case BUF_LAST:
- break;
- default:
- /* Word anchors etc. cannot be handled. It's okay to test
- opr.ctx_type since constraints (for all DFA nodes) are
- created by ORing one or more opr.ctx_type values. */
- return;
- }
- break;
- case OP_PERIOD:
- has_period = true;
- break;
- case OP_BACK_REF:
- case OP_ALT:
- case END_OF_RE:
- case OP_DUP_ASTERISK:
- case OP_OPEN_SUBEXP:
- case OP_CLOSE_SUBEXP:
- break;
- case COMPLEX_BRACKET:
- return;
- case SIMPLE_BRACKET:
- /* Just double check. */
- {
- int rshift = (ASCII_CHARS % BITSET_WORD_BITS == 0
- ? 0
- : BITSET_WORD_BITS - ASCII_CHARS % BITSET_WORD_BITS);
- for (i = ASCII_CHARS / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
- {
- if (dfa->nodes[node].opr.sbcset[i] >> rshift != 0)
- return;
- rshift = 0;
- }
- }
- break;
- default:
- abort ();
- }
-
- if (mb_chars || has_period)
- for (node = 0; node < dfa->nodes_len; ++node)
- {
- if (dfa->nodes[node].type == CHARACTER
- && dfa->nodes[node].opr.c >= ASCII_CHARS)
- dfa->nodes[node].mb_partial = 0;
- else if (dfa->nodes[node].type == OP_PERIOD)
- dfa->nodes[node].type = OP_UTF8_PERIOD;
- }
-
- /* The search can be in single byte locale. */
- dfa->mb_cur_max = 1;
- dfa->is_utf8 = 0;
- dfa->has_mb_node = dfa->nbackref > 0 || has_period;
-}
-#endif
-
-/* Analyze the structure tree, and calculate "first", "next", "edest",
- "eclosure", and "inveclosure". */
-
-static reg_errcode_t
-analyze (regex_t *preg)
-{
- re_dfa_t *dfa = preg->buffer;
- reg_errcode_t ret;
-
- /* Allocate arrays. */
- dfa->nexts = re_malloc (Idx, dfa->nodes_alloc);
- dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc);
- dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
- dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
- if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
- || dfa->eclosures == NULL, 0))
- return REG_ESPACE;
-
- dfa->subexp_map = re_malloc (Idx, preg->re_nsub);
- if (dfa->subexp_map != NULL)
- {
- Idx i;
- for (i = 0; i < preg->re_nsub; i++)
- dfa->subexp_map[i] = i;
- preorder (dfa->str_tree, optimize_subexps, dfa);
- for (i = 0; i < preg->re_nsub; i++)
- if (dfa->subexp_map[i] != i)
- break;
- if (i == preg->re_nsub)
- {
- free (dfa->subexp_map);
- dfa->subexp_map = NULL;
- }
- }
-
- ret = postorder (dfa->str_tree, lower_subexps, preg);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- ret = postorder (dfa->str_tree, calc_first, dfa);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- preorder (dfa->str_tree, calc_next, dfa);
- ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- ret = calc_eclosure (dfa);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
-
- /* We only need this during the prune_impossible_nodes pass in regexec.c;
- skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
- if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
- || dfa->nbackref)
- {
- dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
- if (BE (dfa->inveclosures == NULL, 0))
- return REG_ESPACE;
- ret = calc_inveclosure (dfa);
- }
-
- return ret;
-}
-
-/* Our parse trees are very unbalanced, so we cannot use a stack to
- implement parse tree visits. Instead, we use parent pointers and
- some hairy code in these two functions. */
-static reg_errcode_t
-postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
- void *extra)
-{
- bin_tree_t *node, *prev;
-
- for (node = root; ; )
- {
- /* Descend down the tree, preferably to the left (or to the right
- if that's the only child). */
- while (node->left || node->right)
- if (node->left)
- node = node->left;
- else
- node = node->right;
-
- do
- {
- reg_errcode_t err = fn (extra, node);
- if (BE (err != REG_NOERROR, 0))
- return err;
- if (node->parent == NULL)
- return REG_NOERROR;
- prev = node;
- node = node->parent;
- }
- /* Go up while we have a node that is reached from the right. */
- while (node->right == prev || node->right == NULL);
- node = node->right;
- }
-}
-
-static reg_errcode_t
-preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
- void *extra)
-{
- bin_tree_t *node;
-
- for (node = root; ; )
- {
- reg_errcode_t err = fn (extra, node);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- /* Go to the left node, or up and to the right. */
- if (node->left)
- node = node->left;
- else
- {
- bin_tree_t *prev = NULL;
- while (node->right == prev || node->right == NULL)
- {
- prev = node;
- node = node->parent;
- if (!node)
- return REG_NOERROR;
- }
- node = node->right;
- }
- }
-}
-
-/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
- re_search_internal to map the inner one's opr.idx to this one's. Adjust
- backreferences as well. Requires a preorder visit. */
-static reg_errcode_t
-optimize_subexps (void *extra, bin_tree_t *node)
-{
- re_dfa_t *dfa = (re_dfa_t *) extra;
-
- if (node->token.type == OP_BACK_REF && dfa->subexp_map)
- {
- int idx = node->token.opr.idx;
- node->token.opr.idx = dfa->subexp_map[idx];
- dfa->used_bkref_map |= 1 << node->token.opr.idx;
- }
-
- else if (node->token.type == SUBEXP
- && node->left && node->left->token.type == SUBEXP)
- {
- Idx other_idx = node->left->token.opr.idx;
-
- node->left = node->left->left;
- if (node->left)
- node->left->parent = node;
-
- dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
- if (other_idx < BITSET_WORD_BITS)
- dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
- }
-
- return REG_NOERROR;
-}
-
-/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
- of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
-static reg_errcode_t
-lower_subexps (void *extra, bin_tree_t *node)
-{
- regex_t *preg = (regex_t *) extra;
- reg_errcode_t err = REG_NOERROR;
-
- if (node->left && node->left->token.type == SUBEXP)
- {
- node->left = lower_subexp (&err, preg, node->left);
- if (node->left)
- node->left->parent = node;
- }
- if (node->right && node->right->token.type == SUBEXP)
- {
- node->right = lower_subexp (&err, preg, node->right);
- if (node->right)
- node->right->parent = node;
- }
-
- return err;
-}
-
-static bin_tree_t *
-lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_t *body = node->left;
- bin_tree_t *op, *cls, *tree1, *tree;
-
- if (preg->no_sub
- /* We do not optimize empty subexpressions, because otherwise we may
- have bad CONCAT nodes with NULL children. This is obviously not
- very common, so we do not lose much. An example that triggers
- this case is the sed "script" /\(\)/x. */
- && node->left != NULL
- && (node->token.opr.idx >= BITSET_WORD_BITS
- || !(dfa->used_bkref_map
- & ((bitset_word_t) 1 << node->token.opr.idx))))
- return node->left;
-
- /* Convert the SUBEXP node to the concatenation of an
- OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
- op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
- cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
- tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
- tree = create_tree (dfa, op, tree1, CONCAT);
- if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
-
- op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
- op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
- return tree;
-}
-
-/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
- nodes. Requires a postorder visit. */
-static reg_errcode_t
-calc_first (void *extra, bin_tree_t *node)
-{
- re_dfa_t *dfa = (re_dfa_t *) extra;
- if (node->token.type == CONCAT)
- {
- node->first = node->left->first;
- node->node_idx = node->left->node_idx;
- }
- else
- {
- node->first = node;
- node->node_idx = re_dfa_add_node (dfa, node->token);
- if (BE (node->node_idx == REG_MISSING, 0))
- return REG_ESPACE;
- if (node->token.type == ANCHOR)
- dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type;
- }
- return REG_NOERROR;
-}
-
-/* Pass 2: compute NEXT on the tree. Preorder visit. */
-static reg_errcode_t
-calc_next (void *extra, bin_tree_t *node)
-{
- switch (node->token.type)
- {
- case OP_DUP_ASTERISK:
- node->left->next = node;
- break;
- case CONCAT:
- node->left->next = node->right->first;
- node->right->next = node->next;
- break;
- default:
- if (node->left)
- node->left->next = node->next;
- if (node->right)
- node->right->next = node->next;
- break;
- }
- return REG_NOERROR;
-}
-
-/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
-static reg_errcode_t
-link_nfa_nodes (void *extra, bin_tree_t *node)
-{
- re_dfa_t *dfa = (re_dfa_t *) extra;
- Idx idx = node->node_idx;
- reg_errcode_t err = REG_NOERROR;
-
- switch (node->token.type)
- {
- case CONCAT:
- break;
-
- case END_OF_RE:
- assert (node->next == NULL);
- break;
-
- case OP_DUP_ASTERISK:
- case OP_ALT:
- {
- Idx left, right;
- dfa->has_plural_match = 1;
- if (node->left != NULL)
- left = node->left->first->node_idx;
- else
- left = node->next->node_idx;
- if (node->right != NULL)
- right = node->right->first->node_idx;
- else
- right = node->next->node_idx;
- assert (REG_VALID_INDEX (left));
- assert (REG_VALID_INDEX (right));
- err = re_node_set_init_2 (dfa->edests + idx, left, right);
- }
- break;
-
- case ANCHOR:
- case OP_OPEN_SUBEXP:
- case OP_CLOSE_SUBEXP:
- err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
- break;
-
- case OP_BACK_REF:
- dfa->nexts[idx] = node->next->node_idx;
- if (node->token.type == OP_BACK_REF)
- err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
- break;
-
- default:
- assert (!IS_EPSILON_NODE (node->token.type));
- dfa->nexts[idx] = node->next->node_idx;
- break;
- }
-
- return err;
-}
-
-/* Duplicate the epsilon closure of the node ROOT_NODE.
- Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
- to their own constraint. */
-
-static reg_errcode_t
-internal_function
-duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node, Idx top_clone_node,
- Idx root_node, unsigned int init_constraint)
-{
- Idx org_node, clone_node;
- bool ok;
- unsigned int constraint = init_constraint;
- for (org_node = top_org_node, clone_node = top_clone_node;;)
- {
- Idx org_dest, clone_dest;
- if (dfa->nodes[org_node].type == OP_BACK_REF)
- {
- /* If the back reference epsilon-transit, its destination must
- also have the constraint. Then duplicate the epsilon closure
- of the destination of the back reference, and store it in
- edests of the back reference. */
- org_dest = dfa->nexts[org_node];
- re_node_set_empty (dfa->edests + clone_node);
- clone_dest = duplicate_node (dfa, org_dest, constraint);
- if (BE (clone_dest == REG_MISSING, 0))
- return REG_ESPACE;
- dfa->nexts[clone_node] = dfa->nexts[org_node];
- ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
- else if (dfa->edests[org_node].nelem == 0)
- {
- /* In case of the node can't epsilon-transit, don't duplicate the
- destination and store the original destination as the
- destination of the node. */
- dfa->nexts[clone_node] = dfa->nexts[org_node];
- break;
- }
- else if (dfa->edests[org_node].nelem == 1)
- {
- /* In case of the node can epsilon-transit, and it has only one
- destination. */
- org_dest = dfa->edests[org_node].elems[0];
- re_node_set_empty (dfa->edests + clone_node);
- /* If the node is root_node itself, it means the epsilon closure
- has a loop. Then tie it to the destination of the root_node. */
- if (org_node == root_node && clone_node != org_node)
- {
- ok = re_node_set_insert (dfa->edests + clone_node, org_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- break;
- }
- /* In case the node has another constraint, append it. */
- constraint |= dfa->nodes[org_node].constraint;
- clone_dest = duplicate_node (dfa, org_dest, constraint);
- if (BE (clone_dest == REG_MISSING, 0))
- return REG_ESPACE;
- ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
- else /* dfa->edests[org_node].nelem == 2 */
- {
- /* In case of the node can epsilon-transit, and it has two
- destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
- org_dest = dfa->edests[org_node].elems[0];
- re_node_set_empty (dfa->edests + clone_node);
- /* Search for a duplicated node which satisfies the constraint. */
- clone_dest = search_duplicated_node (dfa, org_dest, constraint);
- if (clone_dest == REG_MISSING)
- {
- /* There is no such duplicated node, create a new one. */
- reg_errcode_t err;
- clone_dest = duplicate_node (dfa, org_dest, constraint);
- if (BE (clone_dest == REG_MISSING, 0))
- return REG_ESPACE;
- ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- err = duplicate_node_closure (dfa, org_dest, clone_dest,
- root_node, constraint);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- else
- {
- /* There is a duplicated node which satisfies the constraint,
- use it to avoid infinite loop. */
- ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
-
- org_dest = dfa->edests[org_node].elems[1];
- clone_dest = duplicate_node (dfa, org_dest, constraint);
- if (BE (clone_dest == REG_MISSING, 0))
- return REG_ESPACE;
- ok = re_node_set_insert (dfa->edests + clone_node, clone_dest);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
- org_node = org_dest;
- clone_node = clone_dest;
- }
- return REG_NOERROR;
-}
-
-/* Search for a node which is duplicated from the node ORG_NODE, and
- satisfies the constraint CONSTRAINT. */
-
-static Idx
-search_duplicated_node (const re_dfa_t *dfa, Idx org_node,
- unsigned int constraint)
-{
- Idx idx;
- for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
- {
- if (org_node == dfa->org_indices[idx]
- && constraint == dfa->nodes[idx].constraint)
- return idx; /* Found. */
- }
- return REG_MISSING; /* Not found. */
-}
-
-/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
- Return the index of the new node, or REG_MISSING if insufficient storage is
- available. */
-
-static Idx
-duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint)
-{
- Idx dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
- if (BE (dup_idx != REG_MISSING, 1))
- {
- dfa->nodes[dup_idx].constraint = constraint;
- dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint;
- dfa->nodes[dup_idx].duplicated = 1;
-
- /* Store the index of the original node. */
- dfa->org_indices[dup_idx] = org_idx;
- }
- return dup_idx;
-}
-
-static reg_errcode_t
-calc_inveclosure (re_dfa_t *dfa)
-{
- Idx src, idx;
- bool ok;
- for (idx = 0; idx < dfa->nodes_len; ++idx)
- re_node_set_init_empty (dfa->inveclosures + idx);
-
- for (src = 0; src < dfa->nodes_len; ++src)
- {
- Idx *elems = dfa->eclosures[src].elems;
- for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
- {
- ok = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
- }
-
- return REG_NOERROR;
-}
-
-/* Calculate "eclosure" for all the node in DFA. */
-
-static reg_errcode_t
-calc_eclosure (re_dfa_t *dfa)
-{
- Idx node_idx;
- bool incomplete;
-#ifdef DEBUG
- assert (dfa->nodes_len > 0);
-#endif
- incomplete = false;
- /* For each nodes, calculate epsilon closure. */
- for (node_idx = 0; ; ++node_idx)
- {
- reg_errcode_t err;
- re_node_set eclosure_elem;
- if (node_idx == dfa->nodes_len)
- {
- if (!incomplete)
- break;
- incomplete = false;
- node_idx = 0;
- }
-
-#ifdef DEBUG
- assert (dfa->eclosures[node_idx].nelem != REG_MISSING);
-#endif
-
- /* If we have already calculated, skip it. */
- if (dfa->eclosures[node_idx].nelem != 0)
- continue;
- /* Calculate epsilon closure of 'node_idx'. */
- err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- if (dfa->eclosures[node_idx].nelem == 0)
- {
- incomplete = true;
- re_node_set_free (&eclosure_elem);
- }
- }
- return REG_NOERROR;
-}
-
-/* Calculate epsilon closure of NODE. */
-
-static reg_errcode_t
-calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
-{
- reg_errcode_t err;
- Idx i;
- re_node_set eclosure;
- bool ok;
- bool incomplete = false;
- err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- /* This indicates that we are calculating this node now.
- We reference this value to avoid infinite loop. */
- dfa->eclosures[node].nelem = REG_MISSING;
-
- /* If the current node has constraints, duplicate all nodes
- since they must inherit the constraints. */
- if (dfa->nodes[node].constraint
- && dfa->edests[node].nelem
- && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
- {
- err = duplicate_node_closure (dfa, node, node, node,
- dfa->nodes[node].constraint);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
-
- /* Expand each epsilon destination nodes. */
- if (IS_EPSILON_NODE(dfa->nodes[node].type))
- for (i = 0; i < dfa->edests[node].nelem; ++i)
- {
- re_node_set eclosure_elem;
- Idx edest = dfa->edests[node].elems[i];
- /* If calculating the epsilon closure of 'edest' is in progress,
- return intermediate result. */
- if (dfa->eclosures[edest].nelem == REG_MISSING)
- {
- incomplete = true;
- continue;
- }
- /* If we haven't calculated the epsilon closure of 'edest' yet,
- calculate now. Otherwise use calculated epsilon closure. */
- if (dfa->eclosures[edest].nelem == 0)
- {
- err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- else
- eclosure_elem = dfa->eclosures[edest];
- /* Merge the epsilon closure of 'edest'. */
- err = re_node_set_merge (&eclosure, &eclosure_elem);
- if (BE (err != REG_NOERROR, 0))
- return err;
- /* If the epsilon closure of 'edest' is incomplete,
- the epsilon closure of this node is also incomplete. */
- if (dfa->eclosures[edest].nelem == 0)
- {
- incomplete = true;
- re_node_set_free (&eclosure_elem);
- }
- }
-
- /* An epsilon closure includes itself. */
- ok = re_node_set_insert (&eclosure, node);
- if (BE (! ok, 0))
- return REG_ESPACE;
- if (incomplete && !root)
- dfa->eclosures[node].nelem = 0;
- else
- dfa->eclosures[node] = eclosure;
- *new_set = eclosure;
- return REG_NOERROR;
-}
-
-/* Functions for token which are used in the parser. */
-
-/* Fetch a token from INPUT.
- We must not use this function inside bracket expressions. */
-
-static void
-internal_function
-fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
-{
- re_string_skip_bytes (input, peek_token (result, input, syntax));
-}
-
-/* Peek a token from INPUT, and return the length of the token.
- We must not use this function inside bracket expressions. */
-
-static int
-internal_function
-peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
-{
- unsigned char c;
-
- if (re_string_eoi (input))
- {
- token->type = END_OF_RE;
- return 0;
- }
-
- c = re_string_peek_byte (input, 0);
- token->opr.c = c;
-
- token->word_char = 0;
-#ifdef RE_ENABLE_I18N
- token->mb_partial = 0;
- if (input->mb_cur_max > 1 &&
- !re_string_first_byte (input, re_string_cur_idx (input)))
- {
- token->type = CHARACTER;
- token->mb_partial = 1;
- return 1;
- }
-#endif
- if (c == '\\')
- {
- unsigned char c2;
- if (re_string_cur_idx (input) + 1 >= re_string_length (input))
- {
- token->type = BACK_SLASH;
- return 1;
- }
-
- c2 = re_string_peek_byte_case (input, 1);
- token->opr.c = c2;
- token->type = CHARACTER;
-#ifdef RE_ENABLE_I18N
- if (input->mb_cur_max > 1)
- {
- wint_t wc = re_string_wchar_at (input,
- re_string_cur_idx (input) + 1);
- token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
- }
- else
-#endif
- token->word_char = IS_WORD_CHAR (c2) != 0;
-
- switch (c2)
- {
- case '|':
- if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
- token->type = OP_ALT;
- break;
- case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- if (!(syntax & RE_NO_BK_REFS))
- {
- token->type = OP_BACK_REF;
- token->opr.idx = c2 - '1';
- }
- break;
- case '<':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = WORD_FIRST;
- }
- break;
- case '>':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = WORD_LAST;
- }
- break;
- case 'b':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = WORD_DELIM;
- }
- break;
- case 'B':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = NOT_WORD_DELIM;
- }
- break;
- case 'w':
- if (!(syntax & RE_NO_GNU_OPS))
- token->type = OP_WORD;
- break;
- case 'W':
- if (!(syntax & RE_NO_GNU_OPS))
- token->type = OP_NOTWORD;
- break;
- case 's':
- if (!(syntax & RE_NO_GNU_OPS))
- token->type = OP_SPACE;
- break;
- case 'S':
- if (!(syntax & RE_NO_GNU_OPS))
- token->type = OP_NOTSPACE;
- break;
- case '`':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = BUF_FIRST;
- }
- break;
- case '\'':
- if (!(syntax & RE_NO_GNU_OPS))
- {
- token->type = ANCHOR;
- token->opr.ctx_type = BUF_LAST;
- }
- break;
- case '(':
- if (!(syntax & RE_NO_BK_PARENS))
- token->type = OP_OPEN_SUBEXP;
- break;
- case ')':
- if (!(syntax & RE_NO_BK_PARENS))
- token->type = OP_CLOSE_SUBEXP;
- break;
- case '+':
- if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
- token->type = OP_DUP_PLUS;
- break;
- case '?':
- if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
- token->type = OP_DUP_QUESTION;
- break;
- case '{':
- if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
- token->type = OP_OPEN_DUP_NUM;
- break;
- case '}':
- if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
- token->type = OP_CLOSE_DUP_NUM;
- break;
- default:
- break;
- }
- return 2;
- }
-
- token->type = CHARACTER;
-#ifdef RE_ENABLE_I18N
- if (input->mb_cur_max > 1)
- {
- wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
- token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
- }
- else
-#endif
- token->word_char = IS_WORD_CHAR (token->opr.c);
-
- switch (c)
- {
- case '\n':
- if (syntax & RE_NEWLINE_ALT)
- token->type = OP_ALT;
- break;
- case '|':
- if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
- token->type = OP_ALT;
- break;
- case '*':
- token->type = OP_DUP_ASTERISK;
- break;
- case '+':
- if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
- token->type = OP_DUP_PLUS;
- break;
- case '?':
- if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
- token->type = OP_DUP_QUESTION;
- break;
- case '{':
- if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
- token->type = OP_OPEN_DUP_NUM;
- break;
- case '}':
- if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
- token->type = OP_CLOSE_DUP_NUM;
- break;
- case '(':
- if (syntax & RE_NO_BK_PARENS)
- token->type = OP_OPEN_SUBEXP;
- break;
- case ')':
- if (syntax & RE_NO_BK_PARENS)
- token->type = OP_CLOSE_SUBEXP;
- break;
- case '[':
- token->type = OP_OPEN_BRACKET;
- break;
- case '.':
- token->type = OP_PERIOD;
- break;
- case '^':
- if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
- re_string_cur_idx (input) != 0)
- {
- char prev = re_string_peek_byte (input, -1);
- if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
- break;
- }
- token->type = ANCHOR;
- token->opr.ctx_type = LINE_FIRST;
- break;
- case '$':
- if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
- re_string_cur_idx (input) + 1 != re_string_length (input))
- {
- re_token_t next;
- re_string_skip_bytes (input, 1);
- peek_token (&next, input, syntax);
- re_string_skip_bytes (input, -1);
- if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
- break;
- }
- token->type = ANCHOR;
- token->opr.ctx_type = LINE_LAST;
- break;
- default:
- break;
- }
- return 1;
-}
-
-/* Peek a token from INPUT, and return the length of the token.
- We must not use this function out of bracket expressions. */
-
-static int
-internal_function
-peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
-{
- unsigned char c;
- if (re_string_eoi (input))
- {
- token->type = END_OF_RE;
- return 0;
- }
- c = re_string_peek_byte (input, 0);
- token->opr.c = c;
-
-#ifdef RE_ENABLE_I18N
- if (input->mb_cur_max > 1 &&
- !re_string_first_byte (input, re_string_cur_idx (input)))
- {
- token->type = CHARACTER;
- return 1;
- }
-#endif /* RE_ENABLE_I18N */
-
- if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
- && re_string_cur_idx (input) + 1 < re_string_length (input))
- {
- /* In this case, '\' escape a character. */
- unsigned char c2;
- re_string_skip_bytes (input, 1);
- c2 = re_string_peek_byte (input, 0);
- token->opr.c = c2;
- token->type = CHARACTER;
- return 1;
- }
- if (c == '[') /* '[' is a special char in a bracket exps. */
- {
- unsigned char c2;
- int token_len;
- if (re_string_cur_idx (input) + 1 < re_string_length (input))
- c2 = re_string_peek_byte (input, 1);
- else
- c2 = 0;
- token->opr.c = c2;
- token_len = 2;
- switch (c2)
- {
- case '.':
- token->type = OP_OPEN_COLL_ELEM;
- break;
- case '=':
- token->type = OP_OPEN_EQUIV_CLASS;
- break;
- case ':':
- if (syntax & RE_CHAR_CLASSES)
- {
- token->type = OP_OPEN_CHAR_CLASS;
- break;
- }
- /* else fall through. */
- default:
- token->type = CHARACTER;
- token->opr.c = c;
- token_len = 1;
- break;
- }
- return token_len;
- }
- switch (c)
- {
- case '-':
- token->type = OP_CHARSET_RANGE;
- break;
- case ']':
- token->type = OP_CLOSE_BRACKET;
- break;
- case '^':
- token->type = OP_NON_MATCH_LIST;
- break;
- default:
- token->type = CHARACTER;
- }
- return 1;
-}
-
-/* Functions for parser. */
-
-/* Entry point of the parser.
- Parse the regular expression REGEXP and return the structure tree.
- If an error occurs, ERR is set by error code, and return NULL.
- This function build the following tree, from regular expression <reg_exp>:
- CAT
- / \
- / \
- <reg_exp> EOR
-
- CAT means concatenation.
- EOR means end of regular expression. */
-
-static bin_tree_t *
-parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
- reg_errcode_t *err)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_t *tree, *eor, *root;
- re_token_t current_token;
- dfa->syntax = syntax;
- fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
- tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- eor = create_tree (dfa, NULL, NULL, END_OF_RE);
- if (tree != NULL)
- root = create_tree (dfa, tree, eor, CONCAT);
- else
- root = eor;
- if (BE (eor == NULL || root == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- return root;
-}
-
-/* This function build the following tree, from regular expression
- <branch1>|<branch2>:
- ALT
- / \
- / \
- <branch1> <branch2>
-
- ALT means alternative, which represents the operator '|'. */
-
-static bin_tree_t *
-parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
- reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_t *tree, *branch = NULL;
- tree = parse_branch (regexp, preg, token, syntax, nest, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
-
- while (token->type == OP_ALT)
- {
- fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
- if (token->type != OP_ALT && token->type != END_OF_RE
- && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
- {
- branch = parse_branch (regexp, preg, token, syntax, nest, err);
- if (BE (*err != REG_NOERROR && branch == NULL, 0))
- return NULL;
- }
- else
- branch = NULL;
- tree = create_tree (dfa, tree, branch, OP_ALT);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- }
- return tree;
-}
-
-/* This function build the following tree, from regular expression
- <exp1><exp2>:
- CAT
- / \
- / \
- <exp1> <exp2>
-
- CAT means concatenation. */
-
-static bin_tree_t *
-parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
- reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
-{
- bin_tree_t *tree, *expr;
- re_dfa_t *dfa = preg->buffer;
- tree = parse_expression (regexp, preg, token, syntax, nest, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
-
- while (token->type != OP_ALT && token->type != END_OF_RE
- && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
- {
- expr = parse_expression (regexp, preg, token, syntax, nest, err);
- if (BE (*err != REG_NOERROR && expr == NULL, 0))
- {
- if (tree != NULL)
- postorder (tree, free_tree, NULL);
- return NULL;
- }
- if (tree != NULL && expr != NULL)
- {
- bin_tree_t *newtree = create_tree (dfa, tree, expr, CONCAT);
- if (newtree == NULL)
- {
- postorder (expr, free_tree, NULL);
- postorder (tree, free_tree, NULL);
- *err = REG_ESPACE;
- return NULL;
- }
- tree = newtree;
- }
- else if (tree == NULL)
- tree = expr;
- /* Otherwise expr == NULL, we don't need to create new tree. */
- }
- return tree;
-}
-
-/* This function build the following tree, from regular expression a*:
- *
- |
- a
-*/
-
-static bin_tree_t *
-parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
- reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_t *tree;
- switch (token->type)
- {
- case CHARACTER:
- tree = create_token_tree (dfa, NULL, NULL, token);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- {
- while (!re_string_eoi (regexp)
- && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
- {
- bin_tree_t *mbc_remain;
- fetch_token (token, regexp, syntax);
- mbc_remain = create_token_tree (dfa, NULL, NULL, token);
- tree = create_tree (dfa, tree, mbc_remain, CONCAT);
- if (BE (mbc_remain == NULL || tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- }
- }
-#endif
- break;
- case OP_OPEN_SUBEXP:
- tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- break;
- case OP_OPEN_BRACKET:
- tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- break;
- case OP_BACK_REF:
- if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
- {
- *err = REG_ESUBREG;
- return NULL;
- }
- dfa->used_bkref_map |= 1 << token->opr.idx;
- tree = create_token_tree (dfa, NULL, NULL, token);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- ++dfa->nbackref;
- dfa->has_mb_node = 1;
- break;
- case OP_OPEN_DUP_NUM:
- if (syntax & RE_CONTEXT_INVALID_DUP)
- {
- *err = REG_BADRPT;
- return NULL;
- }
- /* FALLTHROUGH */
- case OP_DUP_ASTERISK:
- case OP_DUP_PLUS:
- case OP_DUP_QUESTION:
- if (syntax & RE_CONTEXT_INVALID_OPS)
- {
- *err = REG_BADRPT;
- return NULL;
- }
- else if (syntax & RE_CONTEXT_INDEP_OPS)
- {
- fetch_token (token, regexp, syntax);
- return parse_expression (regexp, preg, token, syntax, nest, err);
- }
- /* else fall through */
- case OP_CLOSE_SUBEXP:
- if ((token->type == OP_CLOSE_SUBEXP) &&
- !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
- {
- *err = REG_ERPAREN;
- return NULL;
- }
- /* else fall through */
- case OP_CLOSE_DUP_NUM:
- /* We treat it as a normal character. */
-
- /* Then we can these characters as normal characters. */
- token->type = CHARACTER;
- /* mb_partial and word_char bits should be initialized already
- by peek_token. */
- tree = create_token_tree (dfa, NULL, NULL, token);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- break;
- case ANCHOR:
- if ((token->opr.ctx_type
- & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
- && dfa->word_ops_used == 0)
- init_word_char (dfa);
- if (token->opr.ctx_type == WORD_DELIM
- || token->opr.ctx_type == NOT_WORD_DELIM)
- {
- bin_tree_t *tree_first, *tree_last;
- if (token->opr.ctx_type == WORD_DELIM)
- {
- token->opr.ctx_type = WORD_FIRST;
- tree_first = create_token_tree (dfa, NULL, NULL, token);
- token->opr.ctx_type = WORD_LAST;
- }
- else
- {
- token->opr.ctx_type = INSIDE_WORD;
- tree_first = create_token_tree (dfa, NULL, NULL, token);
- token->opr.ctx_type = INSIDE_NOTWORD;
- }
- tree_last = create_token_tree (dfa, NULL, NULL, token);
- tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
- if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- }
- else
- {
- tree = create_token_tree (dfa, NULL, NULL, token);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- }
- /* We must return here, since ANCHORs can't be followed
- by repetition operators.
- eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
- it must not be "<ANCHOR(^)><REPEAT(*)>". */
- fetch_token (token, regexp, syntax);
- return tree;
- case OP_PERIOD:
- tree = create_token_tree (dfa, NULL, NULL, token);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- if (dfa->mb_cur_max > 1)
- dfa->has_mb_node = 1;
- break;
- case OP_WORD:
- case OP_NOTWORD:
- tree = build_charclass_op (dfa, regexp->trans,
- "alnum",
- "_",
- token->type == OP_NOTWORD, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- break;
- case OP_SPACE:
- case OP_NOTSPACE:
- tree = build_charclass_op (dfa, regexp->trans,
- "space",
- "",
- token->type == OP_NOTSPACE, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- break;
- case OP_ALT:
- case END_OF_RE:
- return NULL;
- case BACK_SLASH:
- *err = REG_EESCAPE;
- return NULL;
- default:
- /* Must not happen? */
-#ifdef DEBUG
- assert (0);
-#endif
- return NULL;
- }
- fetch_token (token, regexp, syntax);
-
- while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
- || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
- {
- tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
- if (BE (*err != REG_NOERROR && tree == NULL, 0))
- return NULL;
- /* In BRE consecutive duplications are not allowed. */
- if ((syntax & RE_CONTEXT_INVALID_DUP)
- && (token->type == OP_DUP_ASTERISK
- || token->type == OP_OPEN_DUP_NUM))
- {
- *err = REG_BADRPT;
- return NULL;
- }
- }
-
- return tree;
-}
-
-/* This function build the following tree, from regular expression
- (<reg_exp>):
- SUBEXP
- |
- <reg_exp>
-*/
-
-static bin_tree_t *
-parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
- reg_syntax_t syntax, Idx nest, reg_errcode_t *err)
-{
- re_dfa_t *dfa = preg->buffer;
- bin_tree_t *tree;
- size_t cur_nsub;
- cur_nsub = preg->re_nsub++;
-
- fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
-
- /* The subexpression may be a null string. */
- if (token->type == OP_CLOSE_SUBEXP)
- tree = NULL;
- else
- {
- tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
- if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
- {
- if (tree != NULL)
- postorder (tree, free_tree, NULL);
- *err = REG_EPAREN;
- }
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
- }
-
- if (cur_nsub <= '9' - '1')
- dfa->completed_bkref_map |= 1 << cur_nsub;
-
- tree = create_tree (dfa, tree, NULL, SUBEXP);
- if (BE (tree == NULL, 0))
- {
- *err = REG_ESPACE;
- return NULL;
- }
- tree->token.opr.idx = cur_nsub;
- return tree;
-}
-
-/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
-
-static bin_tree_t *
-parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
- re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
-{
- bin_tree_t *tree = NULL, *old_tree = NULL;
- Idx i, start, end, start_idx = re_string_cur_idx (regexp);
- re_token_t start_token = *token;
-
- if (token->type == OP_OPEN_DUP_NUM)
- {
- end = 0;
- start = fetch_number (regexp, token, syntax);
- if (start == REG_MISSING)
- {
- if (token->type == CHARACTER && token->opr.c == ',')
- start = 0; /* We treat "{,m}" as "{0,m}". */
- else
- {
- *err = REG_BADBR; /* <re>{} is invalid. */
- return NULL;
- }
- }
- if (BE (start != REG_ERROR, 1))
- {
- /* We treat "{n}" as "{n,n}". */
- end = ((token->type == OP_CLOSE_DUP_NUM) ? start
- : ((token->type == CHARACTER && token->opr.c == ',')
- ? fetch_number (regexp, token, syntax) : REG_ERROR));
- }
- if (BE (start == REG_ERROR || end == REG_ERROR, 0))
- {
- /* Invalid sequence. */
- if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
- {
- if (token->type == END_OF_RE)
- *err = REG_EBRACE;
- else
- *err = REG_BADBR;
-
- return NULL;
- }
-
- /* If the syntax bit is set, rollback. */
- re_string_set_index (regexp, start_idx);
- *token = start_token;
- token->type = CHARACTER;
- /* mb_partial and word_char bits should be already initialized by
- peek_token. */
- return elem;
- }
-
- if (BE ((end != REG_MISSING && start > end)
- || token->type != OP_CLOSE_DUP_NUM, 0))
- {
- /* First number greater than second. */
- *err = REG_BADBR;
- return NULL;
- }
-
- if (BE (RE_DUP_MAX < (end == REG_MISSING ? start : end), 0))
- {
- *err = REG_ESIZE;
- return NULL;
- }
- }
- else
- {
- start = (token->type == OP_DUP_PLUS) ? 1 : 0;
- end = (token->type == OP_DUP_QUESTION) ? 1 : REG_MISSING;
- }
-
- fetch_token (token, regexp, syntax);
-
- if (BE (elem == NULL, 0))
- return NULL;
- if (BE (start == 0 && end == 0, 0))
- {
- postorder (elem, free_tree, NULL);
- return NULL;
- }
-
- /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
- if (BE (start > 0, 0))
- {
- tree = elem;
- for (i = 2; i <= start; ++i)
- {
- elem = duplicate_tree (elem, dfa);
- tree = create_tree (dfa, tree, elem, CONCAT);
- if (BE (elem == NULL || tree == NULL, 0))
- goto parse_dup_op_espace;
- }
-
- if (start == end)
- return tree;
-
- /* Duplicate ELEM before it is marked optional. */
- elem = duplicate_tree (elem, dfa);
- old_tree = tree;
- }
- else
- old_tree = NULL;
-
- if (elem->token.type == SUBEXP)
- {
- uintptr_t subidx = elem->token.opr.idx;
- postorder (elem, mark_opt_subexp, (void *) subidx);
- }
-
- tree = create_tree (dfa, elem, NULL,
- (end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT));
- if (BE (tree == NULL, 0))
- goto parse_dup_op_espace;
-
-/* From gnulib's "intprops.h":
- True if the arithmetic type T is signed. */
-#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
-
- /* This loop is actually executed only when end != REG_MISSING,
- to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
- already created the start+1-th copy. */
- if (TYPE_SIGNED (Idx) || end != REG_MISSING)
- for (i = start + 2; i <= end; ++i)
- {
- elem = duplicate_tree (elem, dfa);
- tree = create_tree (dfa, tree, elem, CONCAT);
- if (BE (elem == NULL || tree == NULL, 0))
- goto parse_dup_op_espace;
-
- tree = create_tree (dfa, tree, NULL, OP_ALT);
- if (BE (tree == NULL, 0))
- goto parse_dup_op_espace;
- }
-
- if (old_tree)
- tree = create_tree (dfa, old_tree, tree, CONCAT);
-
- return tree;
-
- parse_dup_op_espace:
- *err = REG_ESPACE;
- return NULL;
-}
-
-/* Size of the names for collating symbol/equivalence_class/character_class.
- I'm not sure, but maybe enough. */
-#define BRACKET_NAME_BUF_SIZE 32
-
-#ifndef _LIBC
- /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
- Build the range expression which starts from START_ELEM, and ends
- at END_ELEM. The result are written to MBCSET and SBCSET.
- RANGE_ALLOC is the allocated size of mbcset->range_starts, and
- mbcset->range_ends, is a pointer argument since we may
- update it. */
-
-static reg_errcode_t
-internal_function
-# ifdef RE_ENABLE_I18N
-build_range_exp (const reg_syntax_t syntax,
- bitset_t sbcset,
- re_charset_t *mbcset,
- Idx *range_alloc,
- const bracket_elem_t *start_elem,
- const bracket_elem_t *end_elem)
-# else /* not RE_ENABLE_I18N */
-build_range_exp (const reg_syntax_t syntax,
- bitset_t sbcset,
- const bracket_elem_t *start_elem,
- const bracket_elem_t *end_elem)
-# endif /* not RE_ENABLE_I18N */
-{
- unsigned int start_ch, end_ch;
- /* Equivalence Classes and Character Classes can't be a range start/end. */
- if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
- || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
- 0))
- return REG_ERANGE;
-
- /* We can handle no multi character collating elements without libc
- support. */
- if (BE ((start_elem->type == COLL_SYM
- && strlen ((char *) start_elem->opr.name) > 1)
- || (end_elem->type == COLL_SYM
- && strlen ((char *) end_elem->opr.name) > 1), 0))
- return REG_ECOLLATE;
-
-# ifdef RE_ENABLE_I18N
- {
- wchar_t wc;
- wint_t start_wc;
- wint_t end_wc;
-
- start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
- : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
- : 0));
- end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
- : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
- : 0));
- start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
- ? __btowc (start_ch) : start_elem->opr.wch);
- end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
- ? __btowc (end_ch) : end_elem->opr.wch);
- if (start_wc == WEOF || end_wc == WEOF)
- return REG_ECOLLATE;
- else if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_wc > end_wc, 0))
- return REG_ERANGE;
-
- /* Got valid collation sequence values, add them as a new entry.
- However, for !_LIBC we have no collation elements: if the
- character set is single byte, the single byte character set
- that we build below suffices. parse_bracket_exp passes
- no MBCSET if dfa->mb_cur_max == 1. */
- if (mbcset)
- {
- /* Check the space of the arrays. */
- if (BE (*range_alloc == mbcset->nranges, 0))
- {
- /* There is not enough space, need realloc. */
- wchar_t *new_array_start, *new_array_end;
- Idx new_nranges;
-
- /* +1 in case of mbcset->nranges is 0. */
- new_nranges = 2 * mbcset->nranges + 1;
- /* Use realloc since mbcset->range_starts and mbcset->range_ends
- are NULL if *range_alloc == 0. */
- new_array_start = re_realloc (mbcset->range_starts, wchar_t,
- new_nranges);
- new_array_end = re_realloc (mbcset->range_ends, wchar_t,
- new_nranges);
-
- if (BE (new_array_start == NULL || new_array_end == NULL, 0))
- return REG_ESPACE;
-
- mbcset->range_starts = new_array_start;
- mbcset->range_ends = new_array_end;
- *range_alloc = new_nranges;
- }
-
- mbcset->range_starts[mbcset->nranges] = start_wc;
- mbcset->range_ends[mbcset->nranges++] = end_wc;
- }
-
- /* Build the table for single byte characters. */
- for (wc = 0; wc < SBC_MAX; ++wc)
- {
- if (start_wc <= wc && wc <= end_wc)
- bitset_set (sbcset, wc);
- }
- }
-# else /* not RE_ENABLE_I18N */
- {
- unsigned int ch;
- start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
- : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
- : 0));
- end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
- : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
- : 0));
- if (start_ch > end_ch)
- return REG_ERANGE;
- /* Build the table for single byte characters. */
- for (ch = 0; ch < SBC_MAX; ++ch)
- if (start_ch <= ch && ch <= end_ch)
- bitset_set (sbcset, ch);
- }
-# endif /* not RE_ENABLE_I18N */
- return REG_NOERROR;
-}
-#endif /* not _LIBC */
-
-#ifndef _LIBC
-/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
- Build the collating element which is represented by NAME.
- The result are written to MBCSET and SBCSET.
- COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
- pointer argument since we may update it. */
-
-static reg_errcode_t
-internal_function
-# ifdef RE_ENABLE_I18N
-build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
- Idx *coll_sym_alloc, const unsigned char *name)
-# else /* not RE_ENABLE_I18N */
-build_collating_symbol (bitset_t sbcset, const unsigned char *name)
-# endif /* not RE_ENABLE_I18N */
-{
- size_t name_len = strlen ((const char *) name);
- if (BE (name_len != 1, 0))
- return REG_ECOLLATE;
- else
- {
- bitset_set (sbcset, name[0]);
- return REG_NOERROR;
- }
-}
-#endif /* not _LIBC */
-
-/* This function parse bracket expression like "[abc]", "[a-c]",
- "[[.a-a.]]" etc. */
-
-static bin_tree_t *
-parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
- reg_syntax_t syntax, reg_errcode_t *err)
-{
-#ifdef _LIBC
- const unsigned char *collseqmb;
- const char *collseqwc;
- uint32_t nrules;
- int32_t table_size;
- const int32_t *symb_table;
- const unsigned char *extra;
-
- /* Local function for parse_bracket_exp used in _LIBC environment.
- Seek the collating symbol entry corresponding to NAME.
- Return the index of the symbol in the SYMB_TABLE,
- or -1 if not found. */
-
- auto inline int32_t
- __attribute__ ((always_inline))
- seek_collating_symbol_entry (const unsigned char *name, size_t name_len)
- {
- int32_t elem;
-
- for (elem = 0; elem < table_size; elem++)
- if (symb_table[2 * elem] != 0)
- {
- int32_t idx = symb_table[2 * elem + 1];
- /* Skip the name of collating element name. */
- idx += 1 + extra[idx];
- if (/* Compare the length of the name. */
- name_len == extra[idx]
- /* Compare the name. */
- && memcmp (name, &extra[idx + 1], name_len) == 0)
- /* Yep, this is the entry. */
- return elem;
- }
- return -1;
- }
-
- /* Local function for parse_bracket_exp used in _LIBC environment.
- Look up the collation sequence value of BR_ELEM.
- Return the value if succeeded, UINT_MAX otherwise. */
-
- auto inline unsigned int
- __attribute__ ((always_inline))
- lookup_collation_sequence_value (bracket_elem_t *br_elem)
- {
- if (br_elem->type == SB_CHAR)
- {
- /*
- if (MB_CUR_MAX == 1)
- */
- if (nrules == 0)
- return collseqmb[br_elem->opr.ch];
- else
- {
- wint_t wc = __btowc (br_elem->opr.ch);
- return __collseq_table_lookup (collseqwc, wc);
- }
- }
- else if (br_elem->type == MB_CHAR)
- {
- if (nrules != 0)
- return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
- }
- else if (br_elem->type == COLL_SYM)
- {
- size_t sym_name_len = strlen ((char *) br_elem->opr.name);
- if (nrules != 0)
- {
- int32_t elem, idx;
- elem = seek_collating_symbol_entry (br_elem->opr.name,
- sym_name_len);
- if (elem != -1)
- {
- /* We found the entry. */
- idx = symb_table[2 * elem + 1];
- /* Skip the name of collating element name. */
- idx += 1 + extra[idx];
- /* Skip the byte sequence of the collating element. */
- idx += 1 + extra[idx];
- /* Adjust for the alignment. */
- idx = (idx + 3) & ~3;
- /* Skip the multibyte collation sequence value. */
- idx += sizeof (unsigned int);
- /* Skip the wide char sequence of the collating element. */
- idx += sizeof (unsigned int) *
- (1 + *(unsigned int *) (extra + idx));
- /* Return the collation sequence value. */
- return *(unsigned int *) (extra + idx);
- }
- else if (sym_name_len == 1)
- {
- /* No valid character. Match it as a single byte
- character. */
- return collseqmb[br_elem->opr.name[0]];
- }
- }
- else if (sym_name_len == 1)
- return collseqmb[br_elem->opr.name[0]];
- }
- return UINT_MAX;
- }
-
- /* Local function for parse_bracket_exp used in _LIBC environment.
- Build the range expression which starts from START_ELEM, and ends
- at END_ELEM. The result are written to MBCSET and SBCSET.
- RANGE_ALLOC is the allocated size of mbcset->range_starts, and
- mbcset->range_ends, is a pointer argument since we may
- update it. */
-
- auto inline reg_errcode_t
- __attribute__ ((always_inline))
- build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
- bracket_elem_t *start_elem, bracket_elem_t *end_elem)
- {
- unsigned int ch;
- uint32_t start_collseq;
- uint32_t end_collseq;
-
- /* Equivalence Classes and Character Classes can't be a range
- start/end. */
- if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
- || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
- 0))
- return REG_ERANGE;
-
- /* FIXME: Implement rational ranges here, too. */
- start_collseq = lookup_collation_sequence_value (start_elem);
- end_collseq = lookup_collation_sequence_value (end_elem);
- /* Check start/end collation sequence values. */
- if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
- return REG_ECOLLATE;
- if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
- return REG_ERANGE;
-
- /* Got valid collation sequence values, add them as a new entry.
- However, if we have no collation elements, and the character set
- is single byte, the single byte character set that we
- build below suffices. */
- if (nrules > 0 || dfa->mb_cur_max > 1)
- {
- /* Check the space of the arrays. */
- if (BE (*range_alloc == mbcset->nranges, 0))
- {
- /* There is not enough space, need realloc. */
- uint32_t *new_array_start;
- uint32_t *new_array_end;
- Idx new_nranges;
-
- /* +1 in case of mbcset->nranges is 0. */
- new_nranges = 2 * mbcset->nranges + 1;
- new_array_start = re_realloc (mbcset->range_starts, uint32_t,
- new_nranges);
- new_array_end = re_realloc (mbcset->range_ends, uint32_t,
- new_nranges);
-
- if (BE (new_array_start == NULL || new_array_end == NULL, 0))
- return REG_ESPACE;
-
- mbcset->range_starts = new_array_start;
- mbcset->range_ends = new_array_end;
- *range_alloc = new_nranges;
- }
-
- mbcset->range_starts[mbcset->nranges] = start_collseq;
- mbcset->range_ends[mbcset->nranges++] = end_collseq;
- }
-
- /* Build the table for single byte characters. */
- for (ch = 0; ch < SBC_MAX; ch++)
- {
- uint32_t ch_collseq;
- /*
- if (MB_CUR_MAX == 1)
- */
- if (nrules == 0)
- ch_collseq = collseqmb[ch];
- else
- ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
- if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
- bitset_set (sbcset, ch);
- }
- return REG_NOERROR;
- }
-
- /* Local function for parse_bracket_exp used in _LIBC environment.
- Build the collating element which is represented by NAME.
- The result are written to MBCSET and SBCSET.
- COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
- pointer argument since we may update it. */
-
- auto inline reg_errcode_t
- __attribute__ ((always_inline))
- build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
- Idx *coll_sym_alloc, const unsigned char *name)
- {
- int32_t elem, idx;
- size_t name_len = strlen ((const char *) name);
- if (nrules != 0)
- {
- elem = seek_collating_symbol_entry (name, name_len);
- if (elem != -1)
- {
- /* We found the entry. */
- idx = symb_table[2 * elem + 1];
- /* Skip the name of collating element name. */
- idx += 1 + extra[idx];
- }
- else if (name_len == 1)
- {
- /* No valid character, treat it as a normal
- character. */
- bitset_set (sbcset, name[0]);
- return REG_NOERROR;
- }
- else
- return REG_ECOLLATE;
-
- /* Got valid collation sequence, add it as a new entry. */
- /* Check the space of the arrays. */
- if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
- {
- /* Not enough, realloc it. */
- /* +1 in case of mbcset->ncoll_syms is 0. */
- Idx new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
- /* Use realloc since mbcset->coll_syms is NULL
- if *alloc == 0. */
- int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
- new_coll_sym_alloc);
- if (BE (new_coll_syms == NULL, 0))
- return REG_ESPACE;
- mbcset->coll_syms = new_coll_syms;
- *coll_sym_alloc = new_coll_sym_alloc;
- }
- mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
- return REG_NOERROR;
- }
- else
- {
- if (BE (name_len != 1, 0))
- return REG_ECOLLATE;
- else
- {
- bitset_set (sbcset, name[0]);
- return REG_NOERROR;
- }
- }
- }
-#endif
-
- re_token_t br_token;
- re_bitset_ptr_t sbcset;
-#ifdef RE_ENABLE_I18N
- re_charset_t *mbcset;
- Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
- Idx equiv_class_alloc = 0, char_class_alloc = 0;
-#endif /* not RE_ENABLE_I18N */
- bool non_match = false;
- bin_tree_t *work_tree;
- int token_len;
- bool first_round = true;
-#ifdef _LIBC
- collseqmb = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
- nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
- if (nrules)
- {
- /*
- if (MB_CUR_MAX > 1)
- */
- collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
- table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
- symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_SYMB_TABLEMB);
- extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_SYMB_EXTRAMB);
- }
-#endif
- sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
-#ifdef RE_ENABLE_I18N
- mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
-#endif /* RE_ENABLE_I18N */
-#ifdef RE_ENABLE_I18N
- if (BE (sbcset == NULL || mbcset == NULL, 0))
-#else
- if (BE (sbcset == NULL, 0))
-#endif /* RE_ENABLE_I18N */
- {
- re_free (sbcset);
-#ifdef RE_ENABLE_I18N
- re_free (mbcset);
-#endif
- *err = REG_ESPACE;
- return NULL;
- }
-
- token_len = peek_token_bracket (token, regexp, syntax);
- if (BE (token->type == END_OF_RE, 0))
- {
- *err = REG_BADPAT;
- goto parse_bracket_exp_free_return;
- }
- if (token->type == OP_NON_MATCH_LIST)
- {
-#ifdef RE_ENABLE_I18N
- mbcset->non_match = 1;
-#endif /* not RE_ENABLE_I18N */
- non_match = true;
- if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
- bitset_set (sbcset, '\n');
- re_string_skip_bytes (regexp, token_len); /* Skip a token. */
- token_len = peek_token_bracket (token, regexp, syntax);
- if (BE (token->type == END_OF_RE, 0))
- {
- *err = REG_BADPAT;
- goto parse_bracket_exp_free_return;
- }
- }
-
- /* We treat the first ']' as a normal character. */
- if (token->type == OP_CLOSE_BRACKET)
- token->type = CHARACTER;
-
- while (1)
- {
- bracket_elem_t start_elem, end_elem;
- unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
- unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
- reg_errcode_t ret;
- int token_len2 = 0;
- bool is_range_exp = false;
- re_token_t token2;
-
- start_elem.opr.name = start_name_buf;
- ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
- syntax, first_round);
- if (BE (ret != REG_NOERROR, 0))
- {
- *err = ret;
- goto parse_bracket_exp_free_return;
- }
- first_round = false;
-
- /* Get information about the next token. We need it in any case. */
- token_len = peek_token_bracket (token, regexp, syntax);
-
- /* Do not check for ranges if we know they are not allowed. */
- if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
- {
- if (BE (token->type == END_OF_RE, 0))
- {
- *err = REG_EBRACK;
- goto parse_bracket_exp_free_return;
- }
- if (token->type == OP_CHARSET_RANGE)
- {
- re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
- token_len2 = peek_token_bracket (&token2, regexp, syntax);
- if (BE (token2.type == END_OF_RE, 0))
- {
- *err = REG_EBRACK;
- goto parse_bracket_exp_free_return;
- }
- if (token2.type == OP_CLOSE_BRACKET)
- {
- /* We treat the last '-' as a normal character. */
- re_string_skip_bytes (regexp, -token_len);
- token->type = CHARACTER;
- }
- else
- is_range_exp = true;
- }
- }
-
- if (is_range_exp == true)
- {
- end_elem.opr.name = end_name_buf;
- ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
- dfa, syntax, true);
- if (BE (ret != REG_NOERROR, 0))
- {
- *err = ret;
- goto parse_bracket_exp_free_return;
- }
-
- token_len = peek_token_bracket (token, regexp, syntax);
-
-#ifdef _LIBC
- *err = build_range_exp (sbcset, mbcset, &range_alloc,
- &start_elem, &end_elem);
-#else
-# ifdef RE_ENABLE_I18N
- *err = build_range_exp (syntax, sbcset,
- dfa->mb_cur_max > 1 ? mbcset : NULL,
- &range_alloc, &start_elem, &end_elem);
-# else
- *err = build_range_exp (syntax, sbcset, &start_elem, &end_elem);
-# endif
-#endif /* RE_ENABLE_I18N */
- if (BE (*err != REG_NOERROR, 0))
- goto parse_bracket_exp_free_return;
- }
- else
- {
- switch (start_elem.type)
- {
- case SB_CHAR:
- bitset_set (sbcset, start_elem.opr.ch);
- break;
-#ifdef RE_ENABLE_I18N
- case MB_CHAR:
- /* Check whether the array has enough space. */
- if (BE (mbchar_alloc == mbcset->nmbchars, 0))
- {
- wchar_t *new_mbchars;
- /* Not enough, realloc it. */
- /* +1 in case of mbcset->nmbchars is 0. */
- mbchar_alloc = 2 * mbcset->nmbchars + 1;
- /* Use realloc since array is NULL if *alloc == 0. */
- new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
- mbchar_alloc);
- if (BE (new_mbchars == NULL, 0))
- goto parse_bracket_exp_espace;
- mbcset->mbchars = new_mbchars;
- }
- mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
- break;
-#endif /* RE_ENABLE_I18N */
- case EQUIV_CLASS:
- *err = build_equiv_class (sbcset,
-#ifdef RE_ENABLE_I18N
- mbcset, &equiv_class_alloc,
-#endif /* RE_ENABLE_I18N */
- start_elem.opr.name);
- if (BE (*err != REG_NOERROR, 0))
- goto parse_bracket_exp_free_return;
- break;
- case COLL_SYM:
- *err = build_collating_symbol (sbcset,
-#ifdef RE_ENABLE_I18N
- mbcset, &coll_sym_alloc,
-#endif /* RE_ENABLE_I18N */
- start_elem.opr.name);
- if (BE (*err != REG_NOERROR, 0))
- goto parse_bracket_exp_free_return;
- break;
- case CHAR_CLASS:
- *err = build_charclass (regexp->trans, sbcset,
-#ifdef RE_ENABLE_I18N
- mbcset, &char_class_alloc,
-#endif /* RE_ENABLE_I18N */
- (const char *) start_elem.opr.name,
- syntax);
- if (BE (*err != REG_NOERROR, 0))
- goto parse_bracket_exp_free_return;
- break;
- default:
- assert (0);
- break;
- }
- }
- if (BE (token->type == END_OF_RE, 0))
- {
- *err = REG_EBRACK;
- goto parse_bracket_exp_free_return;
- }
- if (token->type == OP_CLOSE_BRACKET)
- break;
- }
-
- re_string_skip_bytes (regexp, token_len); /* Skip a token. */
-
- /* If it is non-matching list. */
- if (non_match)
- bitset_not (sbcset);
-
-#ifdef RE_ENABLE_I18N
- /* Ensure only single byte characters are set. */
- if (dfa->mb_cur_max > 1)
- bitset_mask (sbcset, dfa->sb_char);
-
- if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
- || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
- || mbcset->non_match)))
- {
- bin_tree_t *mbc_tree;
- int sbc_idx;
- /* Build a tree for complex bracket. */
- dfa->has_mb_node = 1;
- br_token.type = COMPLEX_BRACKET;
- br_token.opr.mbcset = mbcset;
- mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
- if (BE (mbc_tree == NULL, 0))
- goto parse_bracket_exp_espace;
- for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
- if (sbcset[sbc_idx])
- break;
- /* If there are no bits set in sbcset, there is no point
- of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
- if (sbc_idx < BITSET_WORDS)
- {
- /* Build a tree for simple bracket. */
- br_token.type = SIMPLE_BRACKET;
- br_token.opr.sbcset = sbcset;
- work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
- if (BE (work_tree == NULL, 0))
- goto parse_bracket_exp_espace;
-
- /* Then join them by ALT node. */
- work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
- if (BE (work_tree == NULL, 0))
- goto parse_bracket_exp_espace;
- }
- else
- {
- re_free (sbcset);
- work_tree = mbc_tree;
- }
- }
- else
-#endif /* not RE_ENABLE_I18N */
- {
-#ifdef RE_ENABLE_I18N
- free_charset (mbcset);
-#endif
- /* Build a tree for simple bracket. */
- br_token.type = SIMPLE_BRACKET;
- br_token.opr.sbcset = sbcset;
- work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
- if (BE (work_tree == NULL, 0))
- goto parse_bracket_exp_espace;
- }
- return work_tree;
-
- parse_bracket_exp_espace:
- *err = REG_ESPACE;
- parse_bracket_exp_free_return:
- re_free (sbcset);
-#ifdef RE_ENABLE_I18N
- free_charset (mbcset);
-#endif /* RE_ENABLE_I18N */
- return NULL;
-}
-
-/* Parse an element in the bracket expression. */
-
-static reg_errcode_t
-parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
- re_token_t *token, int token_len, re_dfa_t *dfa,
- reg_syntax_t syntax, bool accept_hyphen)
-{
-#ifdef RE_ENABLE_I18N
- int cur_char_size;
- cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
- if (cur_char_size > 1)
- {
- elem->type = MB_CHAR;
- elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
- re_string_skip_bytes (regexp, cur_char_size);
- return REG_NOERROR;
- }
-#endif /* RE_ENABLE_I18N */
- re_string_skip_bytes (regexp, token_len); /* Skip a token. */
- if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
- || token->type == OP_OPEN_EQUIV_CLASS)
- return parse_bracket_symbol (elem, regexp, token);
- if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
- {
- /* A '-' must only appear as anything but a range indicator before
- the closing bracket. Everything else is an error. */
- re_token_t token2;
- (void) peek_token_bracket (&token2, regexp, syntax);
- if (token2.type != OP_CLOSE_BRACKET)
- /* The actual error value is not standardized since this whole
- case is undefined. But ERANGE makes good sense. */
- return REG_ERANGE;
- }
- elem->type = SB_CHAR;
- elem->opr.ch = token->opr.c;
- return REG_NOERROR;
-}
-
-/* Parse a bracket symbol in the bracket expression. Bracket symbols are
- such as [:<character_class>:], [.<collating_element>.], and
- [=<equivalent_class>=]. */
-
-static reg_errcode_t
-parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
- re_token_t *token)
-{
- unsigned char ch, delim = token->opr.c;
- int i = 0;
- if (re_string_eoi(regexp))
- return REG_EBRACK;
- for (;; ++i)
- {
- if (i >= BRACKET_NAME_BUF_SIZE)
- return REG_EBRACK;
- if (token->type == OP_OPEN_CHAR_CLASS)
- ch = re_string_fetch_byte_case (regexp);
- else
- ch = re_string_fetch_byte (regexp);
- if (re_string_eoi(regexp))
- return REG_EBRACK;
- if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
- break;
- elem->opr.name[i] = ch;
- }
- re_string_skip_bytes (regexp, 1);
- elem->opr.name[i] = '\0';
- switch (token->type)
- {
- case OP_OPEN_COLL_ELEM:
- elem->type = COLL_SYM;
- break;
- case OP_OPEN_EQUIV_CLASS:
- elem->type = EQUIV_CLASS;
- break;
- case OP_OPEN_CHAR_CLASS:
- elem->type = CHAR_CLASS;
- break;
- default:
- break;
- }
- return REG_NOERROR;
-}
-
- /* Helper function for parse_bracket_exp.
- Build the equivalence class which is represented by NAME.
- The result are written to MBCSET and SBCSET.
- EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
- is a pointer argument since we may update it. */
-
-static reg_errcode_t
-#ifdef RE_ENABLE_I18N
-build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
- Idx *equiv_class_alloc, const unsigned char *name)
-#else /* not RE_ENABLE_I18N */
-build_equiv_class (bitset_t sbcset, const unsigned char *name)
-#endif /* not RE_ENABLE_I18N */
-{
-#ifdef _LIBC
- uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
- if (nrules != 0)
- {
- const int32_t *table, *indirect;
- const unsigned char *weights, *extra, *cp;
- unsigned char char_buf[2];
- int32_t idx1, idx2;
- unsigned int ch;
- size_t len;
- /* This #include defines a local function! */
-# include <locale/weight.h>
- /* Calculate the index for equivalence class. */
- cp = name;
- table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
- weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_WEIGHTMB);
- extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_EXTRAMB);
- indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_INDIRECTMB);
- idx1 = findidx (&cp, -1);
- if (BE (idx1 == 0 || *cp != '\0', 0))
- /* This isn't a valid character. */
- return REG_ECOLLATE;
-
- /* Build single byte matching table for this equivalence class. */
- len = weights[idx1 & 0xffffff];
- for (ch = 0; ch < SBC_MAX; ++ch)
- {
- char_buf[0] = ch;
- cp = char_buf;
- idx2 = findidx (&cp, 1);
-/*
- idx2 = table[ch];
-*/
- if (idx2 == 0)
- /* This isn't a valid character. */
- continue;
- /* Compare only if the length matches and the collation rule
- index is the same. */
- if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24))
- {
- int cnt = 0;
-
- while (cnt <= len &&
- weights[(idx1 & 0xffffff) + 1 + cnt]
- == weights[(idx2 & 0xffffff) + 1 + cnt])
- ++cnt;
-
- if (cnt > len)
- bitset_set (sbcset, ch);
- }
- }
- /* Check whether the array has enough space. */
- if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
- {
- /* Not enough, realloc it. */
- /* +1 in case of mbcset->nequiv_classes is 0. */
- Idx new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
- /* Use realloc since the array is NULL if *alloc == 0. */
- int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
- int32_t,
- new_equiv_class_alloc);
- if (BE (new_equiv_classes == NULL, 0))
- return REG_ESPACE;
- mbcset->equiv_classes = new_equiv_classes;
- *equiv_class_alloc = new_equiv_class_alloc;
- }
- mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
- }
- else
-#endif /* _LIBC */
- {
- if (BE (strlen ((const char *) name) != 1, 0))
- return REG_ECOLLATE;
- bitset_set (sbcset, *name);
- }
- return REG_NOERROR;
-}
-
- /* Helper function for parse_bracket_exp.
- Build the character class which is represented by NAME.
- The result are written to MBCSET and SBCSET.
- CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
- is a pointer argument since we may update it. */
-
-static reg_errcode_t
-#ifdef RE_ENABLE_I18N
-build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
- re_charset_t *mbcset, Idx *char_class_alloc,
- const char *class_name, reg_syntax_t syntax)
-#else /* not RE_ENABLE_I18N */
-build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
- const char *class_name, reg_syntax_t syntax)
-#endif /* not RE_ENABLE_I18N */
-{
- int i;
- const char *name = class_name;
-
- /* In case of REG_ICASE "upper" and "lower" match the both of
- upper and lower cases. */
- if ((syntax & RE_ICASE)
- && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
- name = "alpha";
-
-#ifdef RE_ENABLE_I18N
- /* Check the space of the arrays. */
- if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
- {
- /* Not enough, realloc it. */
- /* +1 in case of mbcset->nchar_classes is 0. */
- Idx new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
- /* Use realloc since array is NULL if *alloc == 0. */
- wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
- new_char_class_alloc);
- if (BE (new_char_classes == NULL, 0))
- return REG_ESPACE;
- mbcset->char_classes = new_char_classes;
- *char_class_alloc = new_char_class_alloc;
- }
- mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
-#endif /* RE_ENABLE_I18N */
-
-#define BUILD_CHARCLASS_LOOP(ctype_func) \
- do { \
- if (BE (trans != NULL, 0)) \
- { \
- for (i = 0; i < SBC_MAX; ++i) \
- if (ctype_func (i)) \
- bitset_set (sbcset, trans[i]); \
- } \
- else \
- { \
- for (i = 0; i < SBC_MAX; ++i) \
- if (ctype_func (i)) \
- bitset_set (sbcset, i); \
- } \
- } while (0)
-
- if (strcmp (name, "alnum") == 0)
- BUILD_CHARCLASS_LOOP (isalnum);
- else if (strcmp (name, "cntrl") == 0)
- BUILD_CHARCLASS_LOOP (iscntrl);
- else if (strcmp (name, "lower") == 0)
- BUILD_CHARCLASS_LOOP (islower);
- else if (strcmp (name, "space") == 0)
- BUILD_CHARCLASS_LOOP (isspace);
- else if (strcmp (name, "alpha") == 0)
- BUILD_CHARCLASS_LOOP (isalpha);
- else if (strcmp (name, "digit") == 0)
- BUILD_CHARCLASS_LOOP (isdigit);
- else if (strcmp (name, "print") == 0)
- BUILD_CHARCLASS_LOOP (isprint);
- else if (strcmp (name, "upper") == 0)
- BUILD_CHARCLASS_LOOP (isupper);
- else if (strcmp (name, "blank") == 0)
- BUILD_CHARCLASS_LOOP (isblank);
- else if (strcmp (name, "graph") == 0)
- BUILD_CHARCLASS_LOOP (isgraph);
- else if (strcmp (name, "punct") == 0)
- BUILD_CHARCLASS_LOOP (ispunct);
- else if (strcmp (name, "xdigit") == 0)
- BUILD_CHARCLASS_LOOP (isxdigit);
- else
- return REG_ECTYPE;
-
- return REG_NOERROR;
-}
-
-static bin_tree_t *
-build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
- const char *class_name,
- const char *extra, bool non_match,
- reg_errcode_t *err)
-{
- re_bitset_ptr_t sbcset;
-#ifdef RE_ENABLE_I18N
- re_charset_t *mbcset;
- Idx alloc = 0;
-#endif /* not RE_ENABLE_I18N */
- reg_errcode_t ret;
- re_token_t br_token;
- bin_tree_t *tree;
-
- sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
-#ifdef RE_ENABLE_I18N
- mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
-#endif /* RE_ENABLE_I18N */
-
-#ifdef RE_ENABLE_I18N
- if (BE (sbcset == NULL || mbcset == NULL, 0))
-#else /* not RE_ENABLE_I18N */
- if (BE (sbcset == NULL, 0))
-#endif /* not RE_ENABLE_I18N */
- {
- *err = REG_ESPACE;
- return NULL;
- }
-
- if (non_match)
- {
-#ifdef RE_ENABLE_I18N
- mbcset->non_match = 1;
-#endif /* not RE_ENABLE_I18N */
- }
-
- /* We don't care the syntax in this case. */
- ret = build_charclass (trans, sbcset,
-#ifdef RE_ENABLE_I18N
- mbcset, &alloc,
-#endif /* RE_ENABLE_I18N */
- class_name, 0);
-
- if (BE (ret != REG_NOERROR, 0))
- {
- re_free (sbcset);
-#ifdef RE_ENABLE_I18N
- free_charset (mbcset);
-#endif /* RE_ENABLE_I18N */
- *err = ret;
- return NULL;
- }
- /* \w match '_' also. */
- for (; *extra; extra++)
- bitset_set (sbcset, *extra);
-
- /* If it is non-matching list. */
- if (non_match)
- bitset_not (sbcset);
-
-#ifdef RE_ENABLE_I18N
- /* Ensure only single byte characters are set. */
- if (dfa->mb_cur_max > 1)
- bitset_mask (sbcset, dfa->sb_char);
-#endif
-
- /* Build a tree for simple bracket. */
- br_token.type = SIMPLE_BRACKET;
- br_token.opr.sbcset = sbcset;
- tree = create_token_tree (dfa, NULL, NULL, &br_token);
- if (BE (tree == NULL, 0))
- goto build_word_op_espace;
-
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- {
- bin_tree_t *mbc_tree;
- /* Build a tree for complex bracket. */
- br_token.type = COMPLEX_BRACKET;
- br_token.opr.mbcset = mbcset;
- dfa->has_mb_node = 1;
- mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
- if (BE (mbc_tree == NULL, 0))
- goto build_word_op_espace;
- /* Then join them by ALT node. */
- tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
- if (BE (mbc_tree != NULL, 1))
- return tree;
- }
- else
- {
- free_charset (mbcset);
- return tree;
- }
-#else /* not RE_ENABLE_I18N */
- return tree;
-#endif /* not RE_ENABLE_I18N */
-
- build_word_op_espace:
- re_free (sbcset);
-#ifdef RE_ENABLE_I18N
- free_charset (mbcset);
-#endif /* RE_ENABLE_I18N */
- *err = REG_ESPACE;
- return NULL;
-}
-
-/* This is intended for the expressions like "a{1,3}".
- Fetch a number from 'input', and return the number.
- Return REG_MISSING if the number field is empty like "{,1}".
- Return RE_DUP_MAX + 1 if the number field is too large.
- Return REG_ERROR if an error occurred. */
-
-static Idx
-fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
-{
- Idx num = REG_MISSING;
- unsigned char c;
- while (1)
- {
- fetch_token (token, input, syntax);
- c = token->opr.c;
- if (BE (token->type == END_OF_RE, 0))
- return REG_ERROR;
- if (token->type == OP_CLOSE_DUP_NUM || c == ',')
- break;
- num = ((token->type != CHARACTER || c < '0' || '9' < c
- || num == REG_ERROR)
- ? REG_ERROR
- : num == REG_MISSING
- ? c - '0'
- : MIN (RE_DUP_MAX + 1, num * 10 + c - '0'));
- }
- return num;
-}
-
-#ifdef RE_ENABLE_I18N
-static void
-free_charset (re_charset_t *cset)
-{
- re_free (cset->mbchars);
-# ifdef _LIBC
- re_free (cset->coll_syms);
- re_free (cset->equiv_classes);
- re_free (cset->range_starts);
- re_free (cset->range_ends);
-# endif
- re_free (cset->char_classes);
- re_free (cset);
-}
-#endif /* RE_ENABLE_I18N */
-
-/* Functions for binary tree operation. */
-
-/* Create a tree node. */
-
-static bin_tree_t *
-create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
- re_token_type_t type)
-{
- re_token_t t;
- t.type = type;
- return create_token_tree (dfa, left, right, &t);
-}
-
-static bin_tree_t *
-create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
- const re_token_t *token)
-{
- bin_tree_t *tree;
- if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
- {
- bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
-
- if (storage == NULL)
- return NULL;
- storage->next = dfa->str_tree_storage;
- dfa->str_tree_storage = storage;
- dfa->str_tree_storage_idx = 0;
- }
- tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
-
- tree->parent = NULL;
- tree->left = left;
- tree->right = right;
- tree->token = *token;
- tree->token.duplicated = 0;
- tree->token.opt_subexp = 0;
- tree->first = NULL;
- tree->next = NULL;
- tree->node_idx = REG_MISSING;
-
- if (left != NULL)
- left->parent = tree;
- if (right != NULL)
- right->parent = tree;
- return tree;
-}
-
-/* Mark the tree SRC as an optional subexpression.
- To be called from preorder or postorder. */
-
-static reg_errcode_t
-mark_opt_subexp (void *extra, bin_tree_t *node)
-{
- Idx idx = (uintptr_t) extra;
- if (node->token.type == SUBEXP && node->token.opr.idx == idx)
- node->token.opt_subexp = 1;
-
- return REG_NOERROR;
-}
-
-/* Free the allocated memory inside NODE. */
-
-static void
-free_token (re_token_t *node)
-{
-#ifdef RE_ENABLE_I18N
- if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
- free_charset (node->opr.mbcset);
- else
-#endif /* RE_ENABLE_I18N */
- if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
- re_free (node->opr.sbcset);
-}
-
-/* Worker function for tree walking. Free the allocated memory inside NODE
- and its children. */
-
-static reg_errcode_t
-free_tree (void *extra, bin_tree_t *node)
-{
- free_token (&node->token);
- return REG_NOERROR;
-}
-
-
-/* Duplicate the node SRC, and return new node. This is a preorder
- visit similar to the one implemented by the generic visitor, but
- we need more infrastructure to maintain two parallel trees --- so,
- it's easier to duplicate. */
-
-static bin_tree_t *
-duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
-{
- const bin_tree_t *node;
- bin_tree_t *dup_root;
- bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
-
- for (node = root; ; )
- {
- /* Create a new tree and link it back to the current parent. */
- *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
- if (*p_new == NULL)
- return NULL;
- (*p_new)->parent = dup_node;
- (*p_new)->token.duplicated = 1;
- dup_node = *p_new;
-
- /* Go to the left node, or up and to the right. */
- if (node->left)
- {
- node = node->left;
- p_new = &dup_node->left;
- }
- else
- {
- const bin_tree_t *prev = NULL;
- while (node->right == prev || node->right == NULL)
- {
- prev = node;
- node = node->parent;
- dup_node = dup_node->parent;
- if (!node)
- return dup_root;
- }
- node = node->right;
- p_new = &dup_node->right;
- }
- }
-}
diff --git a/contrib/tools/bison/lib/regex.c b/contrib/tools/bison/lib/regex.c
deleted file mode 100644
index 85091669c7..0000000000
--- a/contrib/tools/bison/lib/regex.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _LIBC
-# include <config.h>
-
-# if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
-# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
-# endif
-# if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
-# pragma GCC diagnostic ignored "-Wold-style-definition"
-# pragma GCC diagnostic ignored "-Wtype-limits"
-# endif
-#endif
-
-/* Make sure no one compiles this code with a C++ compiler. */
-#if defined __cplusplus && defined _LIBC
-# error "This is C code, use a C compiler"
-#endif
-
-#ifdef _LIBC
-/* We have to keep the namespace clean. */
-# define regfree(preg) __regfree (preg)
-# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
-# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
-# define regerror(errcode, preg, errbuf, errbuf_size) \
- __regerror(errcode, preg, errbuf, errbuf_size)
-# define re_set_registers(bu, re, nu, st, en) \
- __re_set_registers (bu, re, nu, st, en)
-# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
- __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
-# define re_match(bufp, string, size, pos, regs) \
- __re_match (bufp, string, size, pos, regs)
-# define re_search(bufp, string, size, startpos, range, regs) \
- __re_search (bufp, string, size, startpos, range, regs)
-# define re_compile_pattern(pattern, length, bufp) \
- __re_compile_pattern (pattern, length, bufp)
-# define re_set_syntax(syntax) __re_set_syntax (syntax)
-# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
- __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
-# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
-
-# error #include "../locale/localeinfo.h"
-#endif
-
-/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
- GNU regex allows. Include it before <regex.h>, which correctly
- #undefs RE_DUP_MAX and sets it to the right value. */
-#include <limits.h>
-
-#include <regex.h>
-#include "regex_internal.h"
-
-#include "regex_internal.c"
-#include "regcomp.c"
-#include "regexec.c"
-
-/* Binary backward compatibility. */
-#if _LIBC
-# include <shlib-compat.h>
-# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
-link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
-int re_max_failures = 2000;
-# endif
-#endif
diff --git a/contrib/tools/bison/lib/regex.h b/contrib/tools/bison/lib/regex.h
deleted file mode 100644
index 854c6edaf7..0000000000
--- a/contrib/tools/bison/lib/regex.h
+++ /dev/null
@@ -1,667 +0,0 @@
-/* Definitions for data structures and routines for the regular
- expression library.
- Copyright (C) 1985, 1989-1993, 1995-1998, 2000-2003, 2005-2013 Free Software
- Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _REGEX_H
-#define _REGEX_H 1
-
-#include <sys/types.h>
-
-/* Allow the use in C++ code. */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Define __USE_GNU to declare GNU extensions that violate the
- POSIX name space rules. */
-#ifdef _GNU_SOURCE
-# define __USE_GNU 1
-#endif
-
-#ifdef _REGEX_LARGE_OFFSETS
-
-/* Use types and values that are wide enough to represent signed and
- unsigned byte offsets in memory. This currently works only when
- the regex code is used outside of the GNU C library; it is not yet
- supported within glibc itself, and glibc users should not define
- _REGEX_LARGE_OFFSETS. */
-
-/* The type of nonnegative object indexes. Traditionally, GNU regex
- uses 'int' for these. Code that uses __re_idx_t should work
- regardless of whether the type is signed. */
-typedef size_t __re_idx_t;
-
-/* The type of object sizes. */
-typedef size_t __re_size_t;
-
-/* The type of object sizes, in places where the traditional code
- uses unsigned long int. */
-typedef size_t __re_long_size_t;
-
-#else
-
-/* The traditional GNU regex implementation mishandles strings longer
- than INT_MAX. */
-typedef int __re_idx_t;
-typedef unsigned int __re_size_t;
-typedef unsigned long int __re_long_size_t;
-
-#endif
-
-/* The following two types have to be signed and unsigned integer type
- wide enough to hold a value of a pointer. For most ANSI compilers
- ptrdiff_t and size_t should be likely OK. Still size of these two
- types is 2 for Microsoft C. Ugh... */
-typedef long int s_reg_t;
-typedef unsigned long int active_reg_t;
-
-/* The following bits are used to determine the regexp syntax we
- recognize. The set/not-set meanings are chosen so that Emacs syntax
- remains the value 0. The bits are given in alphabetical order, and
- the definitions shifted by one from the previous bit; thus, when we
- add or remove a bit, only one other definition need change. */
-typedef unsigned long int reg_syntax_t;
-
-#ifdef __USE_GNU
-/* If this bit is not set, then \ inside a bracket expression is literal.
- If set, then such a \ quotes the following character. */
-# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
-
-/* If this bit is not set, then + and ? are operators, and \+ and \? are
- literals.
- If set, then \+ and \? are operators and + and ? are literals. */
-# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
-
-/* If this bit is set, then character classes are supported. They are:
- [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
- [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
- If not set, then character classes are not supported. */
-# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
-
-/* If this bit is set, then ^ and $ are always anchors (outside bracket
- expressions, of course).
- If this bit is not set, then it depends:
- ^ is an anchor if it is at the beginning of a regular
- expression or after an open-group or an alternation operator;
- $ is an anchor if it is at the end of a regular expression, or
- before a close-group or an alternation operator.
-
- This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
- POSIX draft 11.2 says that * etc. in leading positions is undefined.
- We already implemented a previous draft which made those constructs
- invalid, though, so we haven't changed the code back. */
-# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
-
-/* If this bit is set, then special characters are always special
- regardless of where they are in the pattern.
- If this bit is not set, then special characters are special only in
- some contexts; otherwise they are ordinary. Specifically,
- * + ? and intervals are only special when not after the beginning,
- open-group, or alternation operator. */
-# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
-
-/* If this bit is set, then *, +, ?, and { cannot be first in an re or
- immediately after an alternation or begin-group operator. */
-# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
-
-/* If this bit is set, then . matches newline.
- If not set, then it doesn't. */
-# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
-
-/* If this bit is set, then . doesn't match NUL.
- If not set, then it does. */
-# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
-
-/* If this bit is set, nonmatching lists [^...] do not match newline.
- If not set, they do. */
-# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
-
-/* If this bit is set, either \{...\} or {...} defines an
- interval, depending on RE_NO_BK_BRACES.
- If not set, \{, \}, {, and } are literals. */
-# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
-
-/* If this bit is set, +, ? and | aren't recognized as operators.
- If not set, they are. */
-# define RE_LIMITED_OPS (RE_INTERVALS << 1)
-
-/* If this bit is set, newline is an alternation operator.
- If not set, newline is literal. */
-# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
-
-/* If this bit is set, then '{...}' defines an interval, and \{ and \}
- are literals.
- If not set, then '\{...\}' defines an interval. */
-# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
-
-/* If this bit is set, (...) defines a group, and \( and \) are literals.
- If not set, \(...\) defines a group, and ( and ) are literals. */
-# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
-
-/* If this bit is set, then \<digit> matches <digit>.
- If not set, then \<digit> is a back-reference. */
-# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
-
-/* If this bit is set, then | is an alternation operator, and \| is literal.
- If not set, then \| is an alternation operator, and | is literal. */
-# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
-
-/* If this bit is set, then an ending range point collating higher
- than the starting range point, as in [z-a], is invalid.
- If not set, then when ending range point collates higher than the
- starting range point, the range is ignored. */
-# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
-
-/* If this bit is set, then an unmatched ) is ordinary.
- If not set, then an unmatched ) is invalid. */
-# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
-
-/* If this bit is set, succeed as soon as we match the whole pattern,
- without further backtracking. */
-# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
-
-/* If this bit is set, do not process the GNU regex operators.
- If not set, then the GNU regex operators are recognized. */
-# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
-
-/* If this bit is set, turn on internal regex debugging.
- If not set, and debugging was on, turn it off.
- This only works if regex.c is compiled -DDEBUG.
- We define this bit always, so that all that's needed to turn on
- debugging is to recompile regex.c; the calling code can always have
- this bit set, and it won't affect anything in the normal case. */
-# define RE_DEBUG (RE_NO_GNU_OPS << 1)
-
-/* If this bit is set, a syntactically invalid interval is treated as
- a string of ordinary characters. For example, the ERE 'a{1' is
- treated as 'a\{1'. */
-# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
-
-/* If this bit is set, then ignore case when matching.
- If not set, then case is significant. */
-# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
-
-/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
- for ^, because it is difficult to scan the regex backwards to find
- whether ^ should be special. */
-# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
-
-/* If this bit is set, then \{ cannot be first in a regex or
- immediately after an alternation, open-group or \} operator. */
-# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
-
-/* If this bit is set, then no_sub will be set to 1 during
- re_compile_pattern. */
-# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
-#endif
-
-/* This global variable defines the particular regexp syntax to use (for
- some interfaces). When a regexp is compiled, the syntax used is
- stored in the pattern buffer, so changing this does not affect
- already-compiled regexps. */
-extern reg_syntax_t re_syntax_options;
-
-#ifdef __USE_GNU
-/* Define combinations of the above bits for the standard possibilities.
- (The [[[ comments delimit what gets put into the Texinfo file, so
- don't delete them!) */
-/* [[[begin syntaxes]]] */
-# define RE_SYNTAX_EMACS 0
-
-# define RE_SYNTAX_AWK \
- (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
- | RE_NO_BK_PARENS | RE_NO_BK_REFS \
- | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
- | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
- | RE_CHAR_CLASSES \
- | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
-
-# define RE_SYNTAX_GNU_AWK \
- ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
- | RE_INVALID_INTERVAL_ORD) \
- & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \
- | RE_CONTEXT_INVALID_OPS ))
-
-# define RE_SYNTAX_POSIX_AWK \
- (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
- | RE_INTERVALS | RE_NO_GNU_OPS \
- | RE_INVALID_INTERVAL_ORD)
-
-# define RE_SYNTAX_GREP \
- (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
- | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
- | RE_NEWLINE_ALT)
-
-# define RE_SYNTAX_EGREP \
- (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
- | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
- | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
- | RE_NO_BK_VBAR)
-
-# define RE_SYNTAX_POSIX_EGREP \
- (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
- | RE_INVALID_INTERVAL_ORD)
-
-/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
-# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
-
-# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
-
-/* Syntax bits common to both basic and extended POSIX regex syntax. */
-# define _RE_SYNTAX_POSIX_COMMON \
- (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
- | RE_INTERVALS | RE_NO_EMPTY_RANGES)
-
-# define RE_SYNTAX_POSIX_BASIC \
- (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
-
-/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
- RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
- isn't minimal, since other operators, such as \`, aren't disabled. */
-# define RE_SYNTAX_POSIX_MINIMAL_BASIC \
- (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
-
-# define RE_SYNTAX_POSIX_EXTENDED \
- (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
- | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
- | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
- | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
-
-/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
- removed and RE_NO_BK_REFS is added. */
-# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
- (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
- | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
- | RE_NO_BK_PARENS | RE_NO_BK_REFS \
- | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
-/* [[[end syntaxes]]] */
-
-/* Maximum number of duplicates an interval can allow. POSIX-conforming
- systems might define this in <limits.h>, but we want our
- value, so remove any previous define. */
-# ifdef _REGEX_INCLUDE_LIMITS_H
-# include <limits.h>
-# endif
-# ifdef RE_DUP_MAX
-# undef RE_DUP_MAX
-# endif
-
-/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored
- the counter as a 2-byte signed integer. This is no longer true, so
- RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to
- ((SIZE_MAX - 9) / 10) if _REGEX_LARGE_OFFSETS is defined.
- However, there would be a huge performance problem if someone
- actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains
- its historical value. */
-# define RE_DUP_MAX (0x7fff)
-#endif
-
-
-/* POSIX 'cflags' bits (i.e., information for 'regcomp'). */
-
-/* If this bit is set, then use extended regular expression syntax.
- If not set, then use basic regular expression syntax. */
-#define REG_EXTENDED 1
-
-/* If this bit is set, then ignore case when matching.
- If not set, then case is significant. */
-#define REG_ICASE (1 << 1)
-
-/* If this bit is set, then anchors do not match at newline
- characters in the string.
- If not set, then anchors do match at newlines. */
-#define REG_NEWLINE (1 << 2)
-
-/* If this bit is set, then report only success or fail in regexec.
- If not set, then returns differ between not matching and errors. */
-#define REG_NOSUB (1 << 3)
-
-
-/* POSIX 'eflags' bits (i.e., information for regexec). */
-
-/* If this bit is set, then the beginning-of-line operator doesn't match
- the beginning of the string (presumably because it's not the
- beginning of a line).
- If not set, then the beginning-of-line operator does match the
- beginning of the string. */
-#define REG_NOTBOL 1
-
-/* Like REG_NOTBOL, except for the end-of-line. */
-#define REG_NOTEOL (1 << 1)
-
-/* Use PMATCH[0] to delimit the start and end of the search in the
- buffer. */
-#define REG_STARTEND (1 << 2)
-
-
-/* If any error codes are removed, changed, or added, update the
- '__re_error_msgid' table in regcomp.c. */
-
-typedef enum
-{
- _REG_ENOSYS = -1, /* This will never happen for this implementation. */
- _REG_NOERROR = 0, /* Success. */
- _REG_NOMATCH, /* Didn't find a match (for regexec). */
-
- /* POSIX regcomp return error codes. (In the order listed in the
- standard.) */
- _REG_BADPAT, /* Invalid pattern. */
- _REG_ECOLLATE, /* Invalid collating element. */
- _REG_ECTYPE, /* Invalid character class name. */
- _REG_EESCAPE, /* Trailing backslash. */
- _REG_ESUBREG, /* Invalid back reference. */
- _REG_EBRACK, /* Unmatched left bracket. */
- _REG_EPAREN, /* Parenthesis imbalance. */
- _REG_EBRACE, /* Unmatched \{. */
- _REG_BADBR, /* Invalid contents of \{\}. */
- _REG_ERANGE, /* Invalid range end. */
- _REG_ESPACE, /* Ran out of memory. */
- _REG_BADRPT, /* No preceding re for repetition op. */
-
- /* Error codes we've added. */
- _REG_EEND, /* Premature end. */
- _REG_ESIZE, /* Too large (e.g., repeat count too large). */
- _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
-} reg_errcode_t;
-
-#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K
-# define REG_ENOSYS _REG_ENOSYS
-#endif
-#define REG_NOERROR _REG_NOERROR
-#define REG_NOMATCH _REG_NOMATCH
-#define REG_BADPAT _REG_BADPAT
-#define REG_ECOLLATE _REG_ECOLLATE
-#define REG_ECTYPE _REG_ECTYPE
-#define REG_EESCAPE _REG_EESCAPE
-#define REG_ESUBREG _REG_ESUBREG
-#define REG_EBRACK _REG_EBRACK
-#define REG_EPAREN _REG_EPAREN
-#define REG_EBRACE _REG_EBRACE
-#define REG_BADBR _REG_BADBR
-#define REG_ERANGE _REG_ERANGE
-#define REG_ESPACE _REG_ESPACE
-#define REG_BADRPT _REG_BADRPT
-#define REG_EEND _REG_EEND
-#define REG_ESIZE _REG_ESIZE
-#define REG_ERPAREN _REG_ERPAREN
-
-/* This data structure represents a compiled pattern. Before calling
- the pattern compiler, the fields 'buffer', 'allocated', 'fastmap',
- and 'translate' can be set. After the pattern has been compiled,
- the fields 're_nsub', 'not_bol' and 'not_eol' are available. All
- other fields are private to the regex routines. */
-
-#ifndef RE_TRANSLATE_TYPE
-# define __RE_TRANSLATE_TYPE unsigned char *
-# ifdef __USE_GNU
-# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE
-# endif
-#endif
-
-#ifdef __USE_GNU
-# define __REPB_PREFIX(name) name
-#else
-# define __REPB_PREFIX(name) __##name
-#endif
-
-struct re_pattern_buffer
-{
- /* Space that holds the compiled pattern. The type
- 'struct re_dfa_t' is private and is not declared here. */
- struct re_dfa_t *__REPB_PREFIX(buffer);
-
- /* Number of bytes to which 'buffer' points. */
- __re_long_size_t __REPB_PREFIX(allocated);
-
- /* Number of bytes actually used in 'buffer'. */
- __re_long_size_t __REPB_PREFIX(used);
-
- /* Syntax setting with which the pattern was compiled. */
- reg_syntax_t __REPB_PREFIX(syntax);
-
- /* Pointer to a fastmap, if any, otherwise zero. re_search uses the
- fastmap, if there is one, to skip over impossible starting points
- for matches. */
- char *__REPB_PREFIX(fastmap);
-
- /* Either a translate table to apply to all characters before
- comparing them, or zero for no translation. The translation is
- applied to a pattern when it is compiled and to a string when it
- is matched. */
- __RE_TRANSLATE_TYPE __REPB_PREFIX(translate);
-
- /* Number of subexpressions found by the compiler. */
- size_t re_nsub;
-
- /* Zero if this pattern cannot match the empty string, one else.
- Well, in truth it's used only in 're_search_2', to see whether or
- not we should use the fastmap, so we don't set this absolutely
- perfectly; see 're_compile_fastmap' (the "duplicate" case). */
- unsigned __REPB_PREFIX(can_be_null) : 1;
-
- /* If REGS_UNALLOCATED, allocate space in the 'regs' structure
- for 'max (RE_NREGS, re_nsub + 1)' groups.
- If REGS_REALLOCATE, reallocate space if necessary.
- If REGS_FIXED, use what's there. */
-#ifdef __USE_GNU
-# define REGS_UNALLOCATED 0
-# define REGS_REALLOCATE 1
-# define REGS_FIXED 2
-#endif
- unsigned __REPB_PREFIX(regs_allocated) : 2;
-
- /* Set to zero when 're_compile_pattern' compiles a pattern; set to
- one by 're_compile_fastmap' if it updates the fastmap. */
- unsigned __REPB_PREFIX(fastmap_accurate) : 1;
-
- /* If set, 're_match_2' does not return information about
- subexpressions. */
- unsigned __REPB_PREFIX(no_sub) : 1;
-
- /* If set, a beginning-of-line anchor doesn't match at the beginning
- of the string. */
- unsigned __REPB_PREFIX(not_bol) : 1;
-
- /* Similarly for an end-of-line anchor. */
- unsigned __REPB_PREFIX(not_eol) : 1;
-
- /* If true, an anchor at a newline matches. */
- unsigned __REPB_PREFIX(newline_anchor) : 1;
-};
-
-typedef struct re_pattern_buffer regex_t;
-
-/* Type for byte offsets within the string. POSIX mandates this. */
-#ifdef _REGEX_LARGE_OFFSETS
-/* POSIX 1003.1-2008 requires that regoff_t be at least as wide as
- ptrdiff_t and ssize_t. We don't know of any hosts where ptrdiff_t
- is wider than ssize_t, so ssize_t is safe. */
-typedef ssize_t regoff_t;
-#else
-/* The traditional GNU regex implementation mishandles strings longer
- than INT_MAX. */
-typedef int regoff_t;
-#endif
-
-
-#ifdef __USE_GNU
-/* This is the structure we store register match data in. See
- regex.texinfo for a full description of what registers match. */
-struct re_registers
-{
- __re_size_t num_regs;
- regoff_t *start;
- regoff_t *end;
-};
-
-
-/* If 'regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
- 're_match_2' returns information about at least this many registers
- the first time a 'regs' structure is passed. */
-# ifndef RE_NREGS
-# define RE_NREGS 30
-# endif
-#endif
-
-
-/* POSIX specification for registers. Aside from the different names than
- 're_registers', POSIX uses an array of structures, instead of a
- structure of arrays. */
-typedef struct
-{
- regoff_t rm_so; /* Byte offset from string's start to substring's start. */
- regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
-} regmatch_t;
-
-/* Declarations for routines. */
-
-#ifdef __USE_GNU
-/* Sets the current default syntax to SYNTAX, and return the old syntax.
- You can also simply assign to the 're_syntax_options' variable. */
-extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
-
-/* Compile the regular expression PATTERN, with length LENGTH
- and syntax given by the global 're_syntax_options', into the buffer
- BUFFER. Return NULL if successful, and an error string if not.
-
- To free the allocated storage, you must call 'regfree' on BUFFER.
- Note that the translate table must either have been initialised by
- 'regcomp', with a malloc'ed value, or set to NULL before calling
- 'regfree'. */
-extern const char *re_compile_pattern (const char *__pattern, size_t __length,
- struct re_pattern_buffer *__buffer);
-
-
-/* Compile a fastmap for the compiled pattern in BUFFER; used to
- accelerate searches. Return 0 if successful and -2 if was an
- internal error. */
-extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
-
-
-/* Search in the string STRING (with length LENGTH) for the pattern
- compiled into BUFFER. Start searching at position START, for RANGE
- characters. Return the starting position of the match, -1 for no
- match, or -2 for an internal error. Also return register
- information in REGS (if REGS and BUFFER->no_sub are nonzero). */
-extern regoff_t re_search (struct re_pattern_buffer *__buffer,
- const char *__string, __re_idx_t __length,
- __re_idx_t __start, regoff_t __range,
- struct re_registers *__regs);
-
-
-/* Like 're_search', but search in the concatenation of STRING1 and
- STRING2. Also, stop searching at index START + STOP. */
-extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer,
- const char *__string1, __re_idx_t __length1,
- const char *__string2, __re_idx_t __length2,
- __re_idx_t __start, regoff_t __range,
- struct re_registers *__regs,
- __re_idx_t __stop);
-
-
-/* Like 're_search', but return how many characters in STRING the regexp
- in BUFFER matched, starting at position START. */
-extern regoff_t re_match (struct re_pattern_buffer *__buffer,
- const char *__string, __re_idx_t __length,
- __re_idx_t __start, struct re_registers *__regs);
-
-
-/* Relates to 're_match' as 're_search_2' relates to 're_search'. */
-extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer,
- const char *__string1, __re_idx_t __length1,
- const char *__string2, __re_idx_t __length2,
- __re_idx_t __start, struct re_registers *__regs,
- __re_idx_t __stop);
-
-
-/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
- ENDS. Subsequent matches using BUFFER and REGS will use this memory
- for recording register information. STARTS and ENDS must be
- allocated with malloc, and must each be at least 'NUM_REGS * sizeof
- (regoff_t)' bytes long.
-
- If NUM_REGS == 0, then subsequent matches should allocate their own
- register data.
-
- Unless this function is called, the first search or match using
- BUFFER will allocate its own register data, without
- freeing the old data. */
-extern void re_set_registers (struct re_pattern_buffer *__buffer,
- struct re_registers *__regs,
- __re_size_t __num_regs,
- regoff_t *__starts, regoff_t *__ends);
-#endif /* Use GNU */
-
-#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD)
-# ifndef _CRAY
-/* 4.2 bsd compatibility. */
-extern char *re_comp (const char *);
-extern int re_exec (const char *);
-# endif
-#endif
-
-/* GCC 2.95 and later have "__restrict"; C99 compilers have
- "restrict", and "configure" may have defined "restrict".
- Other compilers use __restrict, __restrict__, and _Restrict, and
- 'configure' might #define 'restrict' to those words, so pick a
- different name. */
-#ifndef _Restrict_
-# if 199901L <= __STDC_VERSION__
-# define _Restrict_ restrict
-# elif 2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)
-# define _Restrict_ __restrict
-# else
-# define _Restrict_
-# endif
-#endif
-/* gcc 3.1 and up support the [restrict] syntax. Don't trust
- sys/cdefs.h's definition of __restrict_arr, though, as it
- mishandles gcc -ansi -pedantic. */
-#ifndef _Restrict_arr_
-# if ((199901L <= __STDC_VERSION__ \
- || ((3 < __GNUC__ || (3 == __GNUC__ && 1 <= __GNUC_MINOR__)) \
- && !defined __STRICT_ANSI__)) \
- && !defined __GNUG__)
-# define _Restrict_arr_ _Restrict_
-# else
-# define _Restrict_arr_
-# endif
-#endif
-
-/* POSIX compatibility. */
-extern int regcomp (regex_t *_Restrict_ __preg,
- const char *_Restrict_ __pattern,
- int __cflags);
-
-extern int regexec (const regex_t *_Restrict_ __preg,
- const char *_Restrict_ __string, size_t __nmatch,
- regmatch_t __pmatch[_Restrict_arr_],
- int __eflags);
-
-extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
- char *_Restrict_ __errbuf, size_t __errbuf_size);
-
-extern void regfree (regex_t *__preg);
-
-
-#ifdef __cplusplus
-}
-#endif /* C++ */
-
-#endif /* regex.h */
diff --git a/contrib/tools/bison/lib/regex_internal.c b/contrib/tools/bison/lib/regex_internal.c
deleted file mode 100644
index 899b0ae67e..0000000000
--- a/contrib/tools/bison/lib/regex_internal.c
+++ /dev/null
@@ -1,1741 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-static void re_string_construct_common (const char *str, Idx len,
- re_string_t *pstr,
- RE_TRANSLATE_TYPE trans, bool icase,
- const re_dfa_t *dfa) internal_function;
-static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
- const re_node_set *nodes,
- re_hashval_t hash) internal_function;
-static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
- const re_node_set *nodes,
- unsigned int context,
- re_hashval_t hash) internal_function;
-
-/* Functions for string operation. */
-
-/* This function allocate the buffers. It is necessary to call
- re_string_reconstruct before using the object. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_string_allocate (re_string_t *pstr, const char *str, Idx len, Idx init_len,
- RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
-{
- reg_errcode_t ret;
- Idx init_buf_len;
-
- /* Ensure at least one character fits into the buffers. */
- if (init_len < dfa->mb_cur_max)
- init_len = dfa->mb_cur_max;
- init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
- re_string_construct_common (str, len, pstr, trans, icase, dfa);
-
- ret = re_string_realloc_buffers (pstr, init_buf_len);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
-
- pstr->word_char = dfa->word_char;
- pstr->word_ops_used = dfa->word_ops_used;
- pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
- pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
- pstr->valid_raw_len = pstr->valid_len;
- return REG_NOERROR;
-}
-
-/* This function allocate the buffers, and initialize them. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_string_construct (re_string_t *pstr, const char *str, Idx len,
- RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
-{
- reg_errcode_t ret;
- memset (pstr, '\0', sizeof (re_string_t));
- re_string_construct_common (str, len, pstr, trans, icase, dfa);
-
- if (len > 0)
- {
- ret = re_string_realloc_buffers (pstr, len + 1);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- }
- pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
-
- if (icase)
- {
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- {
- while (1)
- {
- ret = build_wcs_upper_buffer (pstr);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- if (pstr->valid_raw_len >= len)
- break;
- if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
- break;
- ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- }
- }
- else
-#endif /* RE_ENABLE_I18N */
- build_upper_buffer (pstr);
- }
- else
- {
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- build_wcs_buffer (pstr);
- else
-#endif /* RE_ENABLE_I18N */
- {
- if (trans != NULL)
- re_string_translate_buffer (pstr);
- else
- {
- pstr->valid_len = pstr->bufs_len;
- pstr->valid_raw_len = pstr->bufs_len;
- }
- }
- }
-
- return REG_NOERROR;
-}
-
-/* Helper functions for re_string_allocate, and re_string_construct. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_string_realloc_buffers (re_string_t *pstr, Idx new_buf_len)
-{
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- {
- wint_t *new_wcs;
-
- /* Avoid overflow in realloc. */
- const size_t max_object_size = MAX (sizeof (wint_t), sizeof (Idx));
- if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_buf_len, 0))
- return REG_ESPACE;
-
- new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
- if (BE (new_wcs == NULL, 0))
- return REG_ESPACE;
- pstr->wcs = new_wcs;
- if (pstr->offsets != NULL)
- {
- Idx *new_offsets = re_realloc (pstr->offsets, Idx, new_buf_len);
- if (BE (new_offsets == NULL, 0))
- return REG_ESPACE;
- pstr->offsets = new_offsets;
- }
- }
-#endif /* RE_ENABLE_I18N */
- if (pstr->mbs_allocated)
- {
- unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
- new_buf_len);
- if (BE (new_mbs == NULL, 0))
- return REG_ESPACE;
- pstr->mbs = new_mbs;
- }
- pstr->bufs_len = new_buf_len;
- return REG_NOERROR;
-}
-
-
-static void
-internal_function
-re_string_construct_common (const char *str, Idx len, re_string_t *pstr,
- RE_TRANSLATE_TYPE trans, bool icase,
- const re_dfa_t *dfa)
-{
- pstr->raw_mbs = (const unsigned char *) str;
- pstr->len = len;
- pstr->raw_len = len;
- pstr->trans = trans;
- pstr->icase = icase;
- pstr->mbs_allocated = (trans != NULL || icase);
- pstr->mb_cur_max = dfa->mb_cur_max;
- pstr->is_utf8 = dfa->is_utf8;
- pstr->map_notascii = dfa->map_notascii;
- pstr->stop = pstr->len;
- pstr->raw_stop = pstr->stop;
-}
-
-#ifdef RE_ENABLE_I18N
-
-/* Build wide character buffer PSTR->WCS.
- If the byte sequence of the string are:
- <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
- Then wide character buffer will be:
- <wc1> , WEOF , <wc2> , WEOF , <wc3>
- We use WEOF for padding, they indicate that the position isn't
- a first byte of a multibyte character.
-
- Note that this function assumes PSTR->VALID_LEN elements are already
- built and starts from PSTR->VALID_LEN. */
-
-static void
-internal_function
-build_wcs_buffer (re_string_t *pstr)
-{
-#ifdef _LIBC
- unsigned char buf[MB_LEN_MAX];
- assert (MB_LEN_MAX >= pstr->mb_cur_max);
-#else
- unsigned char buf[64];
-#endif
- mbstate_t prev_st;
- Idx byte_idx, end_idx, remain_len;
- size_t mbclen;
-
- /* Build the buffers from pstr->valid_len to either pstr->len or
- pstr->bufs_len. */
- end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
- for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
- {
- wchar_t wc;
- const char *p;
-
- remain_len = end_idx - byte_idx;
- prev_st = pstr->cur_state;
- /* Apply the translation if we need. */
- if (BE (pstr->trans != NULL, 0))
- {
- int i, ch;
-
- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
- {
- ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
- buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
- }
- p = (const char *) buf;
- }
- else
- p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
- mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
- if (BE (mbclen == (size_t) -1 || mbclen == 0
- || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len), 0))
- {
- /* We treat these cases as a singlebyte character. */
- mbclen = 1;
- wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
- if (BE (pstr->trans != NULL, 0))
- wc = pstr->trans[wc];
- pstr->cur_state = prev_st;
- }
- else if (BE (mbclen == (size_t) -2, 0))
- {
- /* The buffer doesn't have enough space, finish to build. */
- pstr->cur_state = prev_st;
- break;
- }
-
- /* Write wide character and padding. */
- pstr->wcs[byte_idx++] = wc;
- /* Write paddings. */
- for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
- pstr->wcs[byte_idx++] = WEOF;
- }
- pstr->valid_len = byte_idx;
- pstr->valid_raw_len = byte_idx;
-}
-
-/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
- but for REG_ICASE. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-build_wcs_upper_buffer (re_string_t *pstr)
-{
- mbstate_t prev_st;
- Idx src_idx, byte_idx, end_idx, remain_len;
- size_t mbclen;
-#ifdef _LIBC
- char buf[MB_LEN_MAX];
- assert (MB_LEN_MAX >= pstr->mb_cur_max);
-#else
- char buf[64];
-#endif
-
- byte_idx = pstr->valid_len;
- end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
-
- /* The following optimization assumes that ASCII characters can be
- mapped to wide characters with a simple cast. */
- if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
- {
- while (byte_idx < end_idx)
- {
- wchar_t wc;
-
- if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
- && mbsinit (&pstr->cur_state))
- {
- /* In case of a singlebyte character. */
- pstr->mbs[byte_idx]
- = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
- /* The next step uses the assumption that wchar_t is encoded
- ASCII-safe: all ASCII values can be converted like this. */
- pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
- ++byte_idx;
- continue;
- }
-
- remain_len = end_idx - byte_idx;
- prev_st = pstr->cur_state;
- mbclen = __mbrtowc (&wc,
- ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
- + byte_idx), remain_len, &pstr->cur_state);
- if (BE (mbclen < (size_t) -2, 1))
- {
- wchar_t wcu = wc;
- if (iswlower (wc))
- {
- size_t mbcdlen;
-
- wcu = towupper (wc);
- mbcdlen = wcrtomb (buf, wcu, &prev_st);
- if (BE (mbclen == mbcdlen, 1))
- memcpy (pstr->mbs + byte_idx, buf, mbclen);
- else
- {
- src_idx = byte_idx;
- goto offsets_needed;
- }
- }
- else
- memcpy (pstr->mbs + byte_idx,
- pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
- pstr->wcs[byte_idx++] = wcu;
- /* Write paddings. */
- for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
- pstr->wcs[byte_idx++] = WEOF;
- }
- else if (mbclen == (size_t) -1 || mbclen == 0
- || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
- {
- /* It is an invalid character, an incomplete character
- at the end of the string, or '\0'. Just use the byte. */
- int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
- pstr->mbs[byte_idx] = ch;
- /* And also cast it to wide char. */
- pstr->wcs[byte_idx++] = (wchar_t) ch;
- if (BE (mbclen == (size_t) -1, 0))
- pstr->cur_state = prev_st;
- }
- else
- {
- /* The buffer doesn't have enough space, finish to build. */
- pstr->cur_state = prev_st;
- break;
- }
- }
- pstr->valid_len = byte_idx;
- pstr->valid_raw_len = byte_idx;
- return REG_NOERROR;
- }
- else
- for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
- {
- wchar_t wc;
- const char *p;
- offsets_needed:
- remain_len = end_idx - byte_idx;
- prev_st = pstr->cur_state;
- if (BE (pstr->trans != NULL, 0))
- {
- int i, ch;
-
- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
- {
- ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
- buf[i] = pstr->trans[ch];
- }
- p = (const char *) buf;
- }
- else
- p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
- mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
- if (BE (mbclen < (size_t) -2, 1))
- {
- wchar_t wcu = wc;
- if (iswlower (wc))
- {
- size_t mbcdlen;
-
- wcu = towupper (wc);
- mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
- if (BE (mbclen == mbcdlen, 1))
- memcpy (pstr->mbs + byte_idx, buf, mbclen);
- else if (mbcdlen != (size_t) -1)
- {
- size_t i;
-
- if (byte_idx + mbcdlen > pstr->bufs_len)
- {
- pstr->cur_state = prev_st;
- break;
- }
-
- if (pstr->offsets == NULL)
- {
- pstr->offsets = re_malloc (Idx, pstr->bufs_len);
-
- if (pstr->offsets == NULL)
- return REG_ESPACE;
- }
- if (!pstr->offsets_needed)
- {
- for (i = 0; i < (size_t) byte_idx; ++i)
- pstr->offsets[i] = i;
- pstr->offsets_needed = 1;
- }
-
- memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
- pstr->wcs[byte_idx] = wcu;
- pstr->offsets[byte_idx] = src_idx;
- for (i = 1; i < mbcdlen; ++i)
- {
- pstr->offsets[byte_idx + i]
- = src_idx + (i < mbclen ? i : mbclen - 1);
- pstr->wcs[byte_idx + i] = WEOF;
- }
- pstr->len += mbcdlen - mbclen;
- if (pstr->raw_stop > src_idx)
- pstr->stop += mbcdlen - mbclen;
- end_idx = (pstr->bufs_len > pstr->len)
- ? pstr->len : pstr->bufs_len;
- byte_idx += mbcdlen;
- src_idx += mbclen;
- continue;
- }
- else
- memcpy (pstr->mbs + byte_idx, p, mbclen);
- }
- else
- memcpy (pstr->mbs + byte_idx, p, mbclen);
-
- if (BE (pstr->offsets_needed != 0, 0))
- {
- size_t i;
- for (i = 0; i < mbclen; ++i)
- pstr->offsets[byte_idx + i] = src_idx + i;
- }
- src_idx += mbclen;
-
- pstr->wcs[byte_idx++] = wcu;
- /* Write paddings. */
- for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
- pstr->wcs[byte_idx++] = WEOF;
- }
- else if (mbclen == (size_t) -1 || mbclen == 0
- || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
- {
- /* It is an invalid character or '\0'. Just use the byte. */
- int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
-
- if (BE (pstr->trans != NULL, 0))
- ch = pstr->trans [ch];
- pstr->mbs[byte_idx] = ch;
-
- if (BE (pstr->offsets_needed != 0, 0))
- pstr->offsets[byte_idx] = src_idx;
- ++src_idx;
-
- /* And also cast it to wide char. */
- pstr->wcs[byte_idx++] = (wchar_t) ch;
- if (BE (mbclen == (size_t) -1, 0))
- pstr->cur_state = prev_st;
- }
- else
- {
- /* The buffer doesn't have enough space, finish to build. */
- pstr->cur_state = prev_st;
- break;
- }
- }
- pstr->valid_len = byte_idx;
- pstr->valid_raw_len = src_idx;
- return REG_NOERROR;
-}
-
-/* Skip characters until the index becomes greater than NEW_RAW_IDX.
- Return the index. */
-
-static Idx
-internal_function
-re_string_skip_chars (re_string_t *pstr, Idx new_raw_idx, wint_t *last_wc)
-{
- mbstate_t prev_st;
- Idx rawbuf_idx;
- size_t mbclen;
- wint_t wc = WEOF;
-
- /* Skip the characters which are not necessary to check. */
- for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
- rawbuf_idx < new_raw_idx;)
- {
- wchar_t wc2;
- Idx remain_len = pstr->raw_len - rawbuf_idx;
- prev_st = pstr->cur_state;
- mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx,
- remain_len, &pstr->cur_state);
- if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
- {
- /* We treat these cases as a single byte character. */
- if (mbclen == 0 || remain_len == 0)
- wc = L'\0';
- else
- wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
- mbclen = 1;
- pstr->cur_state = prev_st;
- }
- else
- wc = wc2;
- /* Then proceed the next character. */
- rawbuf_idx += mbclen;
- }
- *last_wc = wc;
- return rawbuf_idx;
-}
-#endif /* RE_ENABLE_I18N */
-
-/* Build the buffer PSTR->MBS, and apply the translation if we need.
- This function is used in case of REG_ICASE. */
-
-static void
-internal_function
-build_upper_buffer (re_string_t *pstr)
-{
- Idx char_idx, end_idx;
- end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
-
- for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
- {
- int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
- if (BE (pstr->trans != NULL, 0))
- ch = pstr->trans[ch];
- if (islower (ch))
- pstr->mbs[char_idx] = toupper (ch);
- else
- pstr->mbs[char_idx] = ch;
- }
- pstr->valid_len = char_idx;
- pstr->valid_raw_len = char_idx;
-}
-
-/* Apply TRANS to the buffer in PSTR. */
-
-static void
-internal_function
-re_string_translate_buffer (re_string_t *pstr)
-{
- Idx buf_idx, end_idx;
- end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
-
- for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
- {
- int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
- pstr->mbs[buf_idx] = pstr->trans[ch];
- }
-
- pstr->valid_len = buf_idx;
- pstr->valid_raw_len = buf_idx;
-}
-
-/* This function re-construct the buffers.
- Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
- convert to upper case in case of REG_ICASE, apply translation. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags)
-{
- Idx offset;
-
- if (BE (pstr->raw_mbs_idx <= idx, 0))
- offset = idx - pstr->raw_mbs_idx;
- else
- {
- /* Reset buffer. */
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
-#endif /* RE_ENABLE_I18N */
- pstr->len = pstr->raw_len;
- pstr->stop = pstr->raw_stop;
- pstr->valid_len = 0;
- pstr->raw_mbs_idx = 0;
- pstr->valid_raw_len = 0;
- pstr->offsets_needed = 0;
- pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
- : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
- if (!pstr->mbs_allocated)
- pstr->mbs = (unsigned char *) pstr->raw_mbs;
- offset = idx;
- }
-
- if (BE (offset != 0, 1))
- {
- /* Should the already checked characters be kept? */
- if (BE (offset < pstr->valid_raw_len, 1))
- {
- /* Yes, move them to the front of the buffer. */
-#ifdef RE_ENABLE_I18N
- if (BE (pstr->offsets_needed, 0))
- {
- Idx low = 0, high = pstr->valid_len, mid;
- do
- {
- mid = (high + low) / 2;
- if (pstr->offsets[mid] > offset)
- high = mid;
- else if (pstr->offsets[mid] < offset)
- low = mid + 1;
- else
- break;
- }
- while (low < high);
- if (pstr->offsets[mid] < offset)
- ++mid;
- pstr->tip_context = re_string_context_at (pstr, mid - 1,
- eflags);
- /* This can be quite complicated, so handle specially
- only the common and easy case where the character with
- different length representation of lower and upper
- case is present at or after offset. */
- if (pstr->valid_len > offset
- && mid == offset && pstr->offsets[mid] == offset)
- {
- memmove (pstr->wcs, pstr->wcs + offset,
- (pstr->valid_len - offset) * sizeof (wint_t));
- memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
- pstr->valid_len -= offset;
- pstr->valid_raw_len -= offset;
- for (low = 0; low < pstr->valid_len; low++)
- pstr->offsets[low] = pstr->offsets[low + offset] - offset;
- }
- else
- {
- /* Otherwise, just find out how long the partial multibyte
- character at offset is and fill it with WEOF/255. */
- pstr->len = pstr->raw_len - idx + offset;
- pstr->stop = pstr->raw_stop - idx + offset;
- pstr->offsets_needed = 0;
- while (mid > 0 && pstr->offsets[mid - 1] == offset)
- --mid;
- while (mid < pstr->valid_len)
- if (pstr->wcs[mid] != WEOF)
- break;
- else
- ++mid;
- if (mid == pstr->valid_len)
- pstr->valid_len = 0;
- else
- {
- pstr->valid_len = pstr->offsets[mid] - offset;
- if (pstr->valid_len)
- {
- for (low = 0; low < pstr->valid_len; ++low)
- pstr->wcs[low] = WEOF;
- memset (pstr->mbs, 255, pstr->valid_len);
- }
- }
- pstr->valid_raw_len = pstr->valid_len;
- }
- }
- else
-#endif
- {
- pstr->tip_context = re_string_context_at (pstr, offset - 1,
- eflags);
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- memmove (pstr->wcs, pstr->wcs + offset,
- (pstr->valid_len - offset) * sizeof (wint_t));
-#endif /* RE_ENABLE_I18N */
- if (BE (pstr->mbs_allocated, 0))
- memmove (pstr->mbs, pstr->mbs + offset,
- pstr->valid_len - offset);
- pstr->valid_len -= offset;
- pstr->valid_raw_len -= offset;
-#if DEBUG
- assert (pstr->valid_len > 0);
-#endif
- }
- }
- else
- {
-#ifdef RE_ENABLE_I18N
- /* No, skip all characters until IDX. */
- Idx prev_valid_len = pstr->valid_len;
-
- if (BE (pstr->offsets_needed, 0))
- {
- pstr->len = pstr->raw_len - idx + offset;
- pstr->stop = pstr->raw_stop - idx + offset;
- pstr->offsets_needed = 0;
- }
-#endif
- pstr->valid_len = 0;
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- {
- Idx wcs_idx;
- wint_t wc = WEOF;
-
- if (pstr->is_utf8)
- {
- const unsigned char *raw, *p, *end;
-
- /* Special case UTF-8. Multi-byte chars start with any
- byte other than 0x80 - 0xbf. */
- raw = pstr->raw_mbs + pstr->raw_mbs_idx;
- end = raw + (offset - pstr->mb_cur_max);
- if (end < pstr->raw_mbs)
- end = pstr->raw_mbs;
- p = raw + offset - 1;
-#ifdef _LIBC
- /* We know the wchar_t encoding is UCS4, so for the simple
- case, ASCII characters, skip the conversion step. */
- if (isascii (*p) && BE (pstr->trans == NULL, 1))
- {
- memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
- /* pstr->valid_len = 0; */
- wc = (wchar_t) *p;
- }
- else
-#endif
- for (; p >= end; --p)
- if ((*p & 0xc0) != 0x80)
- {
- mbstate_t cur_state;
- wchar_t wc2;
- Idx mlen = raw + pstr->len - p;
- unsigned char buf[6];
- size_t mbclen;
-
- const unsigned char *pp = p;
- if (BE (pstr->trans != NULL, 0))
- {
- int i = mlen < 6 ? mlen : 6;
- while (--i >= 0)
- buf[i] = pstr->trans[p[i]];
- pp = buf;
- }
- /* XXX Don't use mbrtowc, we know which conversion
- to use (UTF-8 -> UCS4). */
- memset (&cur_state, 0, sizeof (cur_state));
- mbclen = __mbrtowc (&wc2, (const char *) pp, mlen,
- &cur_state);
- if (raw + offset - p <= mbclen
- && mbclen < (size_t) -2)
- {
- memset (&pstr->cur_state, '\0',
- sizeof (mbstate_t));
- pstr->valid_len = mbclen - (raw + offset - p);
- wc = wc2;
- }
- break;
- }
- }
-
- if (wc == WEOF)
- pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
- if (wc == WEOF)
- pstr->tip_context
- = re_string_context_at (pstr, prev_valid_len - 1, eflags);
- else
- pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
- && IS_WIDE_WORD_CHAR (wc))
- ? CONTEXT_WORD
- : ((IS_WIDE_NEWLINE (wc)
- && pstr->newline_anchor)
- ? CONTEXT_NEWLINE : 0));
- if (BE (pstr->valid_len, 0))
- {
- for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
- pstr->wcs[wcs_idx] = WEOF;
- if (pstr->mbs_allocated)
- memset (pstr->mbs, 255, pstr->valid_len);
- }
- pstr->valid_raw_len = pstr->valid_len;
- }
- else
-#endif /* RE_ENABLE_I18N */
- {
- int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
- pstr->valid_raw_len = 0;
- if (pstr->trans)
- c = pstr->trans[c];
- pstr->tip_context = (bitset_contain (pstr->word_char, c)
- ? CONTEXT_WORD
- : ((IS_NEWLINE (c) && pstr->newline_anchor)
- ? CONTEXT_NEWLINE : 0));
- }
- }
- if (!BE (pstr->mbs_allocated, 0))
- pstr->mbs += offset;
- }
- pstr->raw_mbs_idx = idx;
- pstr->len -= offset;
- pstr->stop -= offset;
-
- /* Then build the buffers. */
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- {
- if (pstr->icase)
- {
- reg_errcode_t ret = build_wcs_upper_buffer (pstr);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- }
- else
- build_wcs_buffer (pstr);
- }
- else
-#endif /* RE_ENABLE_I18N */
- if (BE (pstr->mbs_allocated, 0))
- {
- if (pstr->icase)
- build_upper_buffer (pstr);
- else if (pstr->trans != NULL)
- re_string_translate_buffer (pstr);
- }
- else
- pstr->valid_len = pstr->len;
-
- pstr->cur_idx = 0;
- return REG_NOERROR;
-}
-
-static unsigned char
-internal_function __attribute__ ((pure))
-re_string_peek_byte_case (const re_string_t *pstr, Idx idx)
-{
- int ch;
- Idx off;
-
- /* Handle the common (easiest) cases first. */
- if (BE (!pstr->mbs_allocated, 1))
- return re_string_peek_byte (pstr, idx);
-
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1
- && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
- return re_string_peek_byte (pstr, idx);
-#endif
-
- off = pstr->cur_idx + idx;
-#ifdef RE_ENABLE_I18N
- if (pstr->offsets_needed)
- off = pstr->offsets[off];
-#endif
-
- ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
-
-#ifdef RE_ENABLE_I18N
- /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
- this function returns CAPITAL LETTER I instead of first byte of
- DOTLESS SMALL LETTER I. The latter would confuse the parser,
- since peek_byte_case doesn't advance cur_idx in any way. */
- if (pstr->offsets_needed && !isascii (ch))
- return re_string_peek_byte (pstr, idx);
-#endif
-
- return ch;
-}
-
-static unsigned char
-internal_function
-re_string_fetch_byte_case (re_string_t *pstr)
-{
- if (BE (!pstr->mbs_allocated, 1))
- return re_string_fetch_byte (pstr);
-
-#ifdef RE_ENABLE_I18N
- if (pstr->offsets_needed)
- {
- Idx off;
- int ch;
-
- /* For tr_TR.UTF-8 [[:islower:]] there is
- [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
- in that case the whole multi-byte character and return
- the original letter. On the other side, with
- [[: DOTLESS SMALL LETTER I return [[:I, as doing
- anything else would complicate things too much. */
-
- if (!re_string_first_byte (pstr, pstr->cur_idx))
- return re_string_fetch_byte (pstr);
-
- off = pstr->offsets[pstr->cur_idx];
- ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
-
- if (! isascii (ch))
- return re_string_fetch_byte (pstr);
-
- re_string_skip_bytes (pstr,
- re_string_char_size_at (pstr, pstr->cur_idx));
- return ch;
- }
-#endif
-
- return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
-}
-
-static void
-internal_function
-re_string_destruct (re_string_t *pstr)
-{
-#ifdef RE_ENABLE_I18N
- re_free (pstr->wcs);
- re_free (pstr->offsets);
-#endif /* RE_ENABLE_I18N */
- if (pstr->mbs_allocated)
- re_free (pstr->mbs);
-}
-
-/* Return the context at IDX in INPUT. */
-
-static unsigned int
-internal_function
-re_string_context_at (const re_string_t *input, Idx idx, int eflags)
-{
- int c;
- if (BE (! REG_VALID_INDEX (idx), 0))
- /* In this case, we use the value stored in input->tip_context,
- since we can't know the character in input->mbs[-1] here. */
- return input->tip_context;
- if (BE (idx == input->len, 0))
- return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
- : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
-#ifdef RE_ENABLE_I18N
- if (input->mb_cur_max > 1)
- {
- wint_t wc;
- Idx wc_idx = idx;
- while(input->wcs[wc_idx] == WEOF)
- {
-#ifdef DEBUG
- /* It must not happen. */
- assert (REG_VALID_INDEX (wc_idx));
-#endif
- --wc_idx;
- if (! REG_VALID_INDEX (wc_idx))
- return input->tip_context;
- }
- wc = input->wcs[wc_idx];
- if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
- return CONTEXT_WORD;
- return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
- ? CONTEXT_NEWLINE : 0);
- }
- else
-#endif
- {
- c = re_string_byte_at (input, idx);
- if (bitset_contain (input->word_char, c))
- return CONTEXT_WORD;
- return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
- }
-}
-
-/* Functions for set operation. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_alloc (re_node_set *set, Idx size)
-{
- set->alloc = size;
- set->nelem = 0;
- set->elems = re_malloc (Idx, size);
- if (BE (set->elems == NULL, 0) && (MALLOC_0_IS_NONNULL || size != 0))
- return REG_ESPACE;
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_init_1 (re_node_set *set, Idx elem)
-{
- set->alloc = 1;
- set->nelem = 1;
- set->elems = re_malloc (Idx, 1);
- if (BE (set->elems == NULL, 0))
- {
- set->alloc = set->nelem = 0;
- return REG_ESPACE;
- }
- set->elems[0] = elem;
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_init_2 (re_node_set *set, Idx elem1, Idx elem2)
-{
- set->alloc = 2;
- set->elems = re_malloc (Idx, 2);
- if (BE (set->elems == NULL, 0))
- return REG_ESPACE;
- if (elem1 == elem2)
- {
- set->nelem = 1;
- set->elems[0] = elem1;
- }
- else
- {
- set->nelem = 2;
- if (elem1 < elem2)
- {
- set->elems[0] = elem1;
- set->elems[1] = elem2;
- }
- else
- {
- set->elems[0] = elem2;
- set->elems[1] = elem1;
- }
- }
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
-{
- dest->nelem = src->nelem;
- if (src->nelem > 0)
- {
- dest->alloc = dest->nelem;
- dest->elems = re_malloc (Idx, dest->alloc);
- if (BE (dest->elems == NULL, 0))
- {
- dest->alloc = dest->nelem = 0;
- return REG_ESPACE;
- }
- memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx));
- }
- else
- re_node_set_init_empty (dest);
- return REG_NOERROR;
-}
-
-/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
- DEST. Return value indicate the error code or REG_NOERROR if succeeded.
- Note: We assume dest->elems is NULL, when dest->alloc is 0. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
- const re_node_set *src2)
-{
- Idx i1, i2, is, id, delta, sbase;
- if (src1->nelem == 0 || src2->nelem == 0)
- return REG_NOERROR;
-
- /* We need dest->nelem + 2 * elems_in_intersection; this is a
- conservative estimate. */
- if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
- {
- Idx new_alloc = src1->nelem + src2->nelem + dest->alloc;
- Idx *new_elems = re_realloc (dest->elems, Idx, new_alloc);
- if (BE (new_elems == NULL, 0))
- return REG_ESPACE;
- dest->elems = new_elems;
- dest->alloc = new_alloc;
- }
-
- /* Find the items in the intersection of SRC1 and SRC2, and copy
- into the top of DEST those that are not already in DEST itself. */
- sbase = dest->nelem + src1->nelem + src2->nelem;
- i1 = src1->nelem - 1;
- i2 = src2->nelem - 1;
- id = dest->nelem - 1;
- for (;;)
- {
- if (src1->elems[i1] == src2->elems[i2])
- {
- /* Try to find the item in DEST. Maybe we could binary search? */
- while (REG_VALID_INDEX (id) && dest->elems[id] > src1->elems[i1])
- --id;
-
- if (! REG_VALID_INDEX (id) || dest->elems[id] != src1->elems[i1])
- dest->elems[--sbase] = src1->elems[i1];
-
- if (! REG_VALID_INDEX (--i1) || ! REG_VALID_INDEX (--i2))
- break;
- }
-
- /* Lower the highest of the two items. */
- else if (src1->elems[i1] < src2->elems[i2])
- {
- if (! REG_VALID_INDEX (--i2))
- break;
- }
- else
- {
- if (! REG_VALID_INDEX (--i1))
- break;
- }
- }
-
- id = dest->nelem - 1;
- is = dest->nelem + src1->nelem + src2->nelem - 1;
- delta = is - sbase + 1;
-
- /* Now copy. When DELTA becomes zero, the remaining
- DEST elements are already in place; this is more or
- less the same loop that is in re_node_set_merge. */
- dest->nelem += delta;
- if (delta > 0 && REG_VALID_INDEX (id))
- for (;;)
- {
- if (dest->elems[is] > dest->elems[id])
- {
- /* Copy from the top. */
- dest->elems[id + delta--] = dest->elems[is--];
- if (delta == 0)
- break;
- }
- else
- {
- /* Slide from the bottom. */
- dest->elems[id + delta] = dest->elems[id];
- if (! REG_VALID_INDEX (--id))
- break;
- }
- }
-
- /* Copy remaining SRC elements. */
- memcpy (dest->elems, dest->elems + sbase, delta * sizeof (Idx));
-
- return REG_NOERROR;
-}
-
-/* Calculate the union set of the sets SRC1 and SRC2. And store it to
- DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
- const re_node_set *src2)
-{
- Idx i1, i2, id;
- if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
- {
- dest->alloc = src1->nelem + src2->nelem;
- dest->elems = re_malloc (Idx, dest->alloc);
- if (BE (dest->elems == NULL, 0))
- return REG_ESPACE;
- }
- else
- {
- if (src1 != NULL && src1->nelem > 0)
- return re_node_set_init_copy (dest, src1);
- else if (src2 != NULL && src2->nelem > 0)
- return re_node_set_init_copy (dest, src2);
- else
- re_node_set_init_empty (dest);
- return REG_NOERROR;
- }
- for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
- {
- if (src1->elems[i1] > src2->elems[i2])
- {
- dest->elems[id++] = src2->elems[i2++];
- continue;
- }
- if (src1->elems[i1] == src2->elems[i2])
- ++i2;
- dest->elems[id++] = src1->elems[i1++];
- }
- if (i1 < src1->nelem)
- {
- memcpy (dest->elems + id, src1->elems + i1,
- (src1->nelem - i1) * sizeof (Idx));
- id += src1->nelem - i1;
- }
- else if (i2 < src2->nelem)
- {
- memcpy (dest->elems + id, src2->elems + i2,
- (src2->nelem - i2) * sizeof (Idx));
- id += src2->nelem - i2;
- }
- dest->nelem = id;
- return REG_NOERROR;
-}
-
-/* Calculate the union set of the sets DEST and SRC. And store it to
- DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-re_node_set_merge (re_node_set *dest, const re_node_set *src)
-{
- Idx is, id, sbase, delta;
- if (src == NULL || src->nelem == 0)
- return REG_NOERROR;
- if (dest->alloc < 2 * src->nelem + dest->nelem)
- {
- Idx new_alloc = 2 * (src->nelem + dest->alloc);
- Idx *new_buffer = re_realloc (dest->elems, Idx, new_alloc);
- if (BE (new_buffer == NULL, 0))
- return REG_ESPACE;
- dest->elems = new_buffer;
- dest->alloc = new_alloc;
- }
-
- if (BE (dest->nelem == 0, 0))
- {
- dest->nelem = src->nelem;
- memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx));
- return REG_NOERROR;
- }
-
- /* Copy into the top of DEST the items of SRC that are not
- found in DEST. Maybe we could binary search in DEST? */
- for (sbase = dest->nelem + 2 * src->nelem,
- is = src->nelem - 1, id = dest->nelem - 1;
- REG_VALID_INDEX (is) && REG_VALID_INDEX (id); )
- {
- if (dest->elems[id] == src->elems[is])
- is--, id--;
- else if (dest->elems[id] < src->elems[is])
- dest->elems[--sbase] = src->elems[is--];
- else /* if (dest->elems[id] > src->elems[is]) */
- --id;
- }
-
- if (REG_VALID_INDEX (is))
- {
- /* If DEST is exhausted, the remaining items of SRC must be unique. */
- sbase -= is + 1;
- memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (Idx));
- }
-
- id = dest->nelem - 1;
- is = dest->nelem + 2 * src->nelem - 1;
- delta = is - sbase + 1;
- if (delta == 0)
- return REG_NOERROR;
-
- /* Now copy. When DELTA becomes zero, the remaining
- DEST elements are already in place. */
- dest->nelem += delta;
- for (;;)
- {
- if (dest->elems[is] > dest->elems[id])
- {
- /* Copy from the top. */
- dest->elems[id + delta--] = dest->elems[is--];
- if (delta == 0)
- break;
- }
- else
- {
- /* Slide from the bottom. */
- dest->elems[id + delta] = dest->elems[id];
- if (! REG_VALID_INDEX (--id))
- {
- /* Copy remaining SRC elements. */
- memcpy (dest->elems, dest->elems + sbase,
- delta * sizeof (Idx));
- break;
- }
- }
- }
-
- return REG_NOERROR;
-}
-
-/* Insert the new element ELEM to the re_node_set* SET.
- SET should not already have ELEM.
- Return true if successful. */
-
-static bool
-internal_function __attribute_warn_unused_result__
-re_node_set_insert (re_node_set *set, Idx elem)
-{
- Idx idx;
- /* In case the set is empty. */
- if (set->alloc == 0)
- return BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1);
-
- if (BE (set->nelem, 0) == 0)
- {
- /* We already guaranteed above that set->alloc != 0. */
- set->elems[0] = elem;
- ++set->nelem;
- return true;
- }
-
- /* Realloc if we need. */
- if (set->alloc == set->nelem)
- {
- Idx *new_elems;
- set->alloc = set->alloc * 2;
- new_elems = re_realloc (set->elems, Idx, set->alloc);
- if (BE (new_elems == NULL, 0))
- return false;
- set->elems = new_elems;
- }
-
- /* Move the elements which follows the new element. Test the
- first element separately to skip a check in the inner loop. */
- if (elem < set->elems[0])
- {
- idx = 0;
- for (idx = set->nelem; idx > 0; idx--)
- set->elems[idx] = set->elems[idx - 1];
- }
- else
- {
- for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
- set->elems[idx] = set->elems[idx - 1];
- }
-
- /* Insert the new element. */
- set->elems[idx] = elem;
- ++set->nelem;
- return true;
-}
-
-/* Insert the new element ELEM to the re_node_set* SET.
- SET should not already have any element greater than or equal to ELEM.
- Return true if successful. */
-
-static bool
-internal_function __attribute_warn_unused_result__
-re_node_set_insert_last (re_node_set *set, Idx elem)
-{
- /* Realloc if we need. */
- if (set->alloc == set->nelem)
- {
- Idx *new_elems;
- set->alloc = (set->alloc + 1) * 2;
- new_elems = re_realloc (set->elems, Idx, set->alloc);
- if (BE (new_elems == NULL, 0))
- return false;
- set->elems = new_elems;
- }
-
- /* Insert the new element. */
- set->elems[set->nelem++] = elem;
- return true;
-}
-
-/* Compare two node sets SET1 and SET2.
- Return true if SET1 and SET2 are equivalent. */
-
-static bool
-internal_function __attribute__ ((pure))
-re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
-{
- Idx i;
- if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
- return false;
- for (i = set1->nelem ; REG_VALID_INDEX (--i) ; )
- if (set1->elems[i] != set2->elems[i])
- return false;
- return true;
-}
-
-/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
-
-static Idx
-internal_function __attribute__ ((pure))
-re_node_set_contains (const re_node_set *set, Idx elem)
-{
- __re_size_t idx, right, mid;
- if (! REG_VALID_NONZERO_INDEX (set->nelem))
- return 0;
-
- /* Binary search the element. */
- idx = 0;
- right = set->nelem - 1;
- while (idx < right)
- {
- mid = (idx + right) / 2;
- if (set->elems[mid] < elem)
- idx = mid + 1;
- else
- right = mid;
- }
- return set->elems[idx] == elem ? idx + 1 : 0;
-}
-
-static void
-internal_function
-re_node_set_remove_at (re_node_set *set, Idx idx)
-{
- if (idx < 0 || idx >= set->nelem)
- return;
- --set->nelem;
- for (; idx < set->nelem; idx++)
- set->elems[idx] = set->elems[idx + 1];
-}
-
-
-/* Add the token TOKEN to dfa->nodes, and return the index of the token.
- Or return REG_MISSING if an error occurred. */
-
-static Idx
-internal_function
-re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
-{
- if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
- {
- size_t new_nodes_alloc = dfa->nodes_alloc * 2;
- Idx *new_nexts, *new_indices;
- re_node_set *new_edests, *new_eclosures;
- re_token_t *new_nodes;
-
- /* Avoid overflows in realloc. */
- const size_t max_object_size = MAX (sizeof (re_token_t),
- MAX (sizeof (re_node_set),
- sizeof (Idx)));
- if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_nodes_alloc, 0))
- return REG_MISSING;
-
- new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
- if (BE (new_nodes == NULL, 0))
- return REG_MISSING;
- dfa->nodes = new_nodes;
- new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc);
- new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc);
- new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
- new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
- if (BE (new_nexts == NULL || new_indices == NULL
- || new_edests == NULL || new_eclosures == NULL, 0))
- return REG_MISSING;
- dfa->nexts = new_nexts;
- dfa->org_indices = new_indices;
- dfa->edests = new_edests;
- dfa->eclosures = new_eclosures;
- dfa->nodes_alloc = new_nodes_alloc;
- }
- dfa->nodes[dfa->nodes_len] = token;
- dfa->nodes[dfa->nodes_len].constraint = 0;
-#ifdef RE_ENABLE_I18N
- dfa->nodes[dfa->nodes_len].accept_mb =
- ((token.type == OP_PERIOD && dfa->mb_cur_max > 1)
- || token.type == COMPLEX_BRACKET);
-#endif
- dfa->nexts[dfa->nodes_len] = REG_MISSING;
- re_node_set_init_empty (dfa->edests + dfa->nodes_len);
- re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
- return dfa->nodes_len++;
-}
-
-static re_hashval_t
-internal_function
-calc_state_hash (const re_node_set *nodes, unsigned int context)
-{
- re_hashval_t hash = nodes->nelem + context;
- Idx i;
- for (i = 0 ; i < nodes->nelem ; i++)
- hash += nodes->elems[i];
- return hash;
-}
-
-/* Search for the state whose node_set is equivalent to NODES.
- Return the pointer to the state, if we found it in the DFA.
- Otherwise create the new one and return it. In case of an error
- return NULL and set the error code in ERR.
- Note: - We assume NULL as the invalid state, then it is possible that
- return value is NULL and ERR is REG_NOERROR.
- - We never return non-NULL value in case of any errors, it is for
- optimization. */
-
-static re_dfastate_t *
-internal_function __attribute_warn_unused_result__
-re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
- const re_node_set *nodes)
-{
- re_hashval_t hash;
- re_dfastate_t *new_state;
- struct re_state_table_entry *spot;
- Idx i;
-#ifdef lint
- /* Suppress bogus uninitialized-variable warnings. */
- *err = REG_NOERROR;
-#endif
- if (BE (nodes->nelem == 0, 0))
- {
- *err = REG_NOERROR;
- return NULL;
- }
- hash = calc_state_hash (nodes, 0);
- spot = dfa->state_table + (hash & dfa->state_hash_mask);
-
- for (i = 0 ; i < spot->num ; i++)
- {
- re_dfastate_t *state = spot->array[i];
- if (hash != state->hash)
- continue;
- if (re_node_set_compare (&state->nodes, nodes))
- return state;
- }
-
- /* There are no appropriate state in the dfa, create the new one. */
- new_state = create_ci_newstate (dfa, nodes, hash);
- if (BE (new_state == NULL, 0))
- *err = REG_ESPACE;
-
- return new_state;
-}
-
-/* Search for the state whose node_set is equivalent to NODES and
- whose context is equivalent to CONTEXT.
- Return the pointer to the state, if we found it in the DFA.
- Otherwise create the new one and return it. In case of an error
- return NULL and set the error code in ERR.
- Note: - We assume NULL as the invalid state, then it is possible that
- return value is NULL and ERR is REG_NOERROR.
- - We never return non-NULL value in case of any errors, it is for
- optimization. */
-
-static re_dfastate_t *
-internal_function __attribute_warn_unused_result__
-re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
- const re_node_set *nodes, unsigned int context)
-{
- re_hashval_t hash;
- re_dfastate_t *new_state;
- struct re_state_table_entry *spot;
- Idx i;
-#ifdef lint
- /* Suppress bogus uninitialized-variable warnings. */
- *err = REG_NOERROR;
-#endif
- if (nodes->nelem == 0)
- {
- *err = REG_NOERROR;
- return NULL;
- }
- hash = calc_state_hash (nodes, context);
- spot = dfa->state_table + (hash & dfa->state_hash_mask);
-
- for (i = 0 ; i < spot->num ; i++)
- {
- re_dfastate_t *state = spot->array[i];
- if (state->hash == hash
- && state->context == context
- && re_node_set_compare (state->entrance_nodes, nodes))
- return state;
- }
- /* There are no appropriate state in 'dfa', create the new one. */
- new_state = create_cd_newstate (dfa, nodes, context, hash);
- if (BE (new_state == NULL, 0))
- *err = REG_ESPACE;
-
- return new_state;
-}
-
-/* Finish initialization of the new state NEWSTATE, and using its hash value
- HASH put in the appropriate bucket of DFA's state table. Return value
- indicates the error code if failed. */
-
-static reg_errcode_t
-__attribute_warn_unused_result__
-register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
- re_hashval_t hash)
-{
- struct re_state_table_entry *spot;
- reg_errcode_t err;
- Idx i;
-
- newstate->hash = hash;
- err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
- if (BE (err != REG_NOERROR, 0))
- return REG_ESPACE;
- for (i = 0; i < newstate->nodes.nelem; i++)
- {
- Idx elem = newstate->nodes.elems[i];
- if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
- if (! re_node_set_insert_last (&newstate->non_eps_nodes, elem))
- return REG_ESPACE;
- }
-
- spot = dfa->state_table + (hash & dfa->state_hash_mask);
- if (BE (spot->alloc <= spot->num, 0))
- {
- Idx new_alloc = 2 * spot->num + 2;
- re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
- new_alloc);
- if (BE (new_array == NULL, 0))
- return REG_ESPACE;
- spot->array = new_array;
- spot->alloc = new_alloc;
- }
- spot->array[spot->num++] = newstate;
- return REG_NOERROR;
-}
-
-static void
-free_state (re_dfastate_t *state)
-{
- re_node_set_free (&state->non_eps_nodes);
- re_node_set_free (&state->inveclosure);
- if (state->entrance_nodes != &state->nodes)
- {
- re_node_set_free (state->entrance_nodes);
- re_free (state->entrance_nodes);
- }
- re_node_set_free (&state->nodes);
- re_free (state->word_trtable);
- re_free (state->trtable);
- re_free (state);
-}
-
-/* Create the new state which is independent of contexts.
- Return the new state if succeeded, otherwise return NULL. */
-
-static re_dfastate_t *
-internal_function __attribute_warn_unused_result__
-create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
- re_hashval_t hash)
-{
- Idx i;
- reg_errcode_t err;
- re_dfastate_t *newstate;
-
- newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
- if (BE (newstate == NULL, 0))
- return NULL;
- err = re_node_set_init_copy (&newstate->nodes, nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_free (newstate);
- return NULL;
- }
-
- newstate->entrance_nodes = &newstate->nodes;
- for (i = 0 ; i < nodes->nelem ; i++)
- {
- re_token_t *node = dfa->nodes + nodes->elems[i];
- re_token_type_t type = node->type;
- if (type == CHARACTER && !node->constraint)
- continue;
-#ifdef RE_ENABLE_I18N
- newstate->accept_mb |= node->accept_mb;
-#endif /* RE_ENABLE_I18N */
-
- /* If the state has the halt node, the state is a halt state. */
- if (type == END_OF_RE)
- newstate->halt = 1;
- else if (type == OP_BACK_REF)
- newstate->has_backref = 1;
- else if (type == ANCHOR || node->constraint)
- newstate->has_constraint = 1;
- }
- err = register_state (dfa, newstate, hash);
- if (BE (err != REG_NOERROR, 0))
- {
- free_state (newstate);
- newstate = NULL;
- }
- return newstate;
-}
-
-/* Create the new state which is depend on the context CONTEXT.
- Return the new state if succeeded, otherwise return NULL. */
-
-static re_dfastate_t *
-internal_function __attribute_warn_unused_result__
-create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
- unsigned int context, re_hashval_t hash)
-{
- Idx i, nctx_nodes = 0;
- reg_errcode_t err;
- re_dfastate_t *newstate;
-
- newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
- if (BE (newstate == NULL, 0))
- return NULL;
- err = re_node_set_init_copy (&newstate->nodes, nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_free (newstate);
- return NULL;
- }
-
- newstate->context = context;
- newstate->entrance_nodes = &newstate->nodes;
-
- for (i = 0 ; i < nodes->nelem ; i++)
- {
- re_token_t *node = dfa->nodes + nodes->elems[i];
- re_token_type_t type = node->type;
- unsigned int constraint = node->constraint;
-
- if (type == CHARACTER && !constraint)
- continue;
-#ifdef RE_ENABLE_I18N
- newstate->accept_mb |= node->accept_mb;
-#endif /* RE_ENABLE_I18N */
-
- /* If the state has the halt node, the state is a halt state. */
- if (type == END_OF_RE)
- newstate->halt = 1;
- else if (type == OP_BACK_REF)
- newstate->has_backref = 1;
-
- if (constraint)
- {
- if (newstate->entrance_nodes == &newstate->nodes)
- {
- newstate->entrance_nodes = re_malloc (re_node_set, 1);
- if (BE (newstate->entrance_nodes == NULL, 0))
- {
- free_state (newstate);
- return NULL;
- }
- if (re_node_set_init_copy (newstate->entrance_nodes, nodes)
- != REG_NOERROR)
- return NULL;
- nctx_nodes = 0;
- newstate->has_constraint = 1;
- }
-
- if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
- {
- re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
- ++nctx_nodes;
- }
- }
- }
- err = register_state (dfa, newstate, hash);
- if (BE (err != REG_NOERROR, 0))
- {
- free_state (newstate);
- newstate = NULL;
- }
- return newstate;
-}
diff --git a/contrib/tools/bison/lib/regex_internal.h b/contrib/tools/bison/lib/regex_internal.h
deleted file mode 100644
index 6205dbe726..0000000000
--- a/contrib/tools/bison/lib/regex_internal.h
+++ /dev/null
@@ -1,909 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-#ifndef _REGEX_INTERNAL_H
-#define _REGEX_INTERNAL_H 1
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <langinfo.h>
-#include <locale.h>
-#include <wchar.h>
-#include <wctype.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef _LIBC
-# include <bits/libc-lock.h>
-# define lock_define(name) __libc_lock_define (, name)
-# define lock_init(lock) (__libc_lock_init (lock), 0)
-# define lock_fini(lock) 0
-# define lock_lock(lock) __libc_lock_lock (lock)
-# define lock_unlock(lock) __libc_lock_unlock (lock)
-#elif defined GNULIB_LOCK
-# include "glthread/lock.h"
- /* Use gl_lock_define if empty macro arguments are known to work.
- Otherwise, fall back on less-portable substitutes. */
-# if ((defined __GNUC__ && !defined __STRICT_ANSI__) \
- || (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__))
-# define lock_define(name) gl_lock_define (, name)
-# elif USE_POSIX_THREADS
-# define lock_define(name) pthread_mutex_t name;
-# elif USE_PTH_THREADS
-# define lock_define(name) pth_mutex_t name;
-# elif USE_SOLARIS_THREADS
-# define lock_define(name) mutex_t name;
-# elif USE_WINDOWS_THREADS
-# define lock_define(name) gl_lock_t name;
-# else
-# define lock_define(name)
-# endif
-# define lock_init(lock) glthread_lock_init (&(lock))
-# define lock_fini(lock) glthread_lock_destroy (&(lock))
-# define lock_lock(lock) glthread_lock_lock (&(lock))
-# define lock_unlock(lock) glthread_lock_unlock (&(lock))
-#elif defined GNULIB_PTHREAD
-# include <pthread.h>
-# define lock_define(name) pthread_mutex_t name;
-# define lock_init(lock) pthread_mutex_init (&(lock), 0)
-# define lock_fini(lock) pthread_mutex_destroy (&(lock))
-# define lock_lock(lock) pthread_mutex_lock (&(lock))
-# define lock_unlock(lock) pthread_mutex_unlock (&(lock))
-#else
-# define lock_define(name)
-# define lock_init(lock) 0
-# define lock_fini(lock) ((void) 0)
- /* The 'dfa' avoids an "unused variable 'dfa'" warning from GCC. */
-# define lock_lock(lock) ((void) dfa)
-# define lock_unlock(lock) ((void) 0)
-#endif
-
-/* In case that the system doesn't have isblank(). */
-#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK))
-# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
-#endif
-
-#ifdef _LIBC
-# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
-# define _RE_DEFINE_LOCALE_FUNCTIONS 1
-# include <locale/localeinfo.h>
-# include <locale/elem-hash.h>
-# include <locale/coll-lookup.h>
-# endif
-#endif
-
-/* This is for other GNU distributions with internationalized messages. */
-#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
-# include <libintl.h>
-# ifdef _LIBC
-# undef gettext
-# define gettext(msgid) \
- __dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES)
-# endif
-#else
-# define gettext(msgid) (msgid)
-#endif
-
-#ifndef gettext_noop
-/* This define is so xgettext can find the internationalizable
- strings. */
-# define gettext_noop(String) String
-#endif
-
-#if (defined MB_CUR_MAX && HAVE_WCTYPE_H && HAVE_ISWCTYPE && HAVE_WCSCOLL) || _LIBC
-# define RE_ENABLE_I18N
-#endif
-
-#if __GNUC__ >= 3
-# define BE(expr, val) __builtin_expect (expr, val)
-#else
-# define BE(expr, val) (expr)
-#endif
-
-/* Number of ASCII characters. */
-#define ASCII_CHARS 0x80
-
-/* Number of single byte characters. */
-#define SBC_MAX (UCHAR_MAX + 1)
-
-#define COLL_ELEM_LEN_MAX 8
-
-/* The character which represents newline. */
-#define NEWLINE_CHAR '\n'
-#define WIDE_NEWLINE_CHAR L'\n'
-
-/* Rename to standard API for using out of glibc. */
-#ifndef _LIBC
-# undef __wctype
-# undef __iswctype
-# define __wctype wctype
-# define __iswctype iswctype
-# define __btowc btowc
-# define __mbrtowc mbrtowc
-# define __wcrtomb wcrtomb
-# define __regfree regfree
-# define attribute_hidden
-#endif /* not _LIBC */
-
-#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1)
-# define __attribute__(arg)
-#endif
-
-typedef __re_idx_t Idx;
-#ifdef _REGEX_LARGE_OFFSETS
-# define IDX_MAX (SIZE_MAX - 2)
-#else
-# define IDX_MAX INT_MAX
-#endif
-
-/* Special return value for failure to match. */
-#define REG_MISSING ((Idx) -1)
-
-/* Special return value for internal error. */
-#define REG_ERROR ((Idx) -2)
-
-/* Test whether N is a valid index, and is not one of the above. */
-#ifdef _REGEX_LARGE_OFFSETS
-# define REG_VALID_INDEX(n) ((Idx) (n) < REG_ERROR)
-#else
-# define REG_VALID_INDEX(n) (0 <= (n))
-#endif
-
-/* Test whether N is a valid nonzero index. */
-#ifdef _REGEX_LARGE_OFFSETS
-# define REG_VALID_NONZERO_INDEX(n) ((Idx) ((n) - 1) < (Idx) (REG_ERROR - 1))
-#else
-# define REG_VALID_NONZERO_INDEX(n) (0 < (n))
-#endif
-
-/* A hash value, suitable for computing hash tables. */
-typedef __re_size_t re_hashval_t;
-
-/* An integer used to represent a set of bits. It must be unsigned,
- and must be at least as wide as unsigned int. */
-typedef unsigned long int bitset_word_t;
-/* All bits set in a bitset_word_t. */
-#define BITSET_WORD_MAX ULONG_MAX
-
-/* Number of bits in a bitset_word_t. For portability to hosts with
- padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)';
- instead, deduce it directly from BITSET_WORD_MAX. Avoid
- greater-than-32-bit integers and unconditional shifts by more than
- 31 bits, as they're not portable. */
-#if BITSET_WORD_MAX == 0xffffffffUL
-# define BITSET_WORD_BITS 32
-#elif BITSET_WORD_MAX >> 31 >> 4 == 1
-# define BITSET_WORD_BITS 36
-#elif BITSET_WORD_MAX >> 31 >> 16 == 1
-# define BITSET_WORD_BITS 48
-#elif BITSET_WORD_MAX >> 31 >> 28 == 1
-# define BITSET_WORD_BITS 60
-#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1
-# define BITSET_WORD_BITS 64
-#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1
-# define BITSET_WORD_BITS 72
-#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1
-# define BITSET_WORD_BITS 128
-#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1
-# define BITSET_WORD_BITS 256
-#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1
-# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */
-# if BITSET_WORD_BITS <= SBC_MAX
-# error "Invalid SBC_MAX"
-# endif
-#else
-# error "Add case for new bitset_word_t size"
-#endif
-
-/* Number of bitset_word_t values in a bitset_t. */
-#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS)
-
-typedef bitset_word_t bitset_t[BITSET_WORDS];
-typedef bitset_word_t *re_bitset_ptr_t;
-typedef const bitset_word_t *re_const_bitset_ptr_t;
-
-#define PREV_WORD_CONSTRAINT 0x0001
-#define PREV_NOTWORD_CONSTRAINT 0x0002
-#define NEXT_WORD_CONSTRAINT 0x0004
-#define NEXT_NOTWORD_CONSTRAINT 0x0008
-#define PREV_NEWLINE_CONSTRAINT 0x0010
-#define NEXT_NEWLINE_CONSTRAINT 0x0020
-#define PREV_BEGBUF_CONSTRAINT 0x0040
-#define NEXT_ENDBUF_CONSTRAINT 0x0080
-#define WORD_DELIM_CONSTRAINT 0x0100
-#define NOT_WORD_DELIM_CONSTRAINT 0x0200
-
-typedef enum
-{
- INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
- WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
- WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
- INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
- LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
- LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
- BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
- BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
- WORD_DELIM = WORD_DELIM_CONSTRAINT,
- NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
-} re_context_type;
-
-typedef struct
-{
- Idx alloc;
- Idx nelem;
- Idx *elems;
-} re_node_set;
-
-typedef enum
-{
- NON_TYPE = 0,
-
- /* Node type, These are used by token, node, tree. */
- CHARACTER = 1,
- END_OF_RE = 2,
- SIMPLE_BRACKET = 3,
- OP_BACK_REF = 4,
- OP_PERIOD = 5,
-#ifdef RE_ENABLE_I18N
- COMPLEX_BRACKET = 6,
- OP_UTF8_PERIOD = 7,
-#endif /* RE_ENABLE_I18N */
-
- /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
- when the debugger shows values of this enum type. */
-#define EPSILON_BIT 8
- OP_OPEN_SUBEXP = EPSILON_BIT | 0,
- OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
- OP_ALT = EPSILON_BIT | 2,
- OP_DUP_ASTERISK = EPSILON_BIT | 3,
- ANCHOR = EPSILON_BIT | 4,
-
- /* Tree type, these are used only by tree. */
- CONCAT = 16,
- SUBEXP = 17,
-
- /* Token type, these are used only by token. */
- OP_DUP_PLUS = 18,
- OP_DUP_QUESTION,
- OP_OPEN_BRACKET,
- OP_CLOSE_BRACKET,
- OP_CHARSET_RANGE,
- OP_OPEN_DUP_NUM,
- OP_CLOSE_DUP_NUM,
- OP_NON_MATCH_LIST,
- OP_OPEN_COLL_ELEM,
- OP_CLOSE_COLL_ELEM,
- OP_OPEN_EQUIV_CLASS,
- OP_CLOSE_EQUIV_CLASS,
- OP_OPEN_CHAR_CLASS,
- OP_CLOSE_CHAR_CLASS,
- OP_WORD,
- OP_NOTWORD,
- OP_SPACE,
- OP_NOTSPACE,
- BACK_SLASH
-
-} re_token_type_t;
-
-#ifdef RE_ENABLE_I18N
-typedef struct
-{
- /* Multibyte characters. */
- wchar_t *mbchars;
-
- /* Collating symbols. */
-# ifdef _LIBC
- int32_t *coll_syms;
-# endif
-
- /* Equivalence classes. */
-# ifdef _LIBC
- int32_t *equiv_classes;
-# endif
-
- /* Range expressions. */
-# ifdef _LIBC
- uint32_t *range_starts;
- uint32_t *range_ends;
-# else /* not _LIBC */
- wchar_t *range_starts;
- wchar_t *range_ends;
-# endif /* not _LIBC */
-
- /* Character classes. */
- wctype_t *char_classes;
-
- /* If this character set is the non-matching list. */
- unsigned int non_match : 1;
-
- /* # of multibyte characters. */
- Idx nmbchars;
-
- /* # of collating symbols. */
- Idx ncoll_syms;
-
- /* # of equivalence classes. */
- Idx nequiv_classes;
-
- /* # of range expressions. */
- Idx nranges;
-
- /* # of character classes. */
- Idx nchar_classes;
-} re_charset_t;
-#endif /* RE_ENABLE_I18N */
-
-typedef struct
-{
- union
- {
- unsigned char c; /* for CHARACTER */
- re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
-#ifdef RE_ENABLE_I18N
- re_charset_t *mbcset; /* for COMPLEX_BRACKET */
-#endif /* RE_ENABLE_I18N */
- Idx idx; /* for BACK_REF */
- re_context_type ctx_type; /* for ANCHOR */
- } opr;
-#if __GNUC__ >= 2 && !defined __STRICT_ANSI__
- re_token_type_t type : 8;
-#else
- re_token_type_t type;
-#endif
- unsigned int constraint : 10; /* context constraint */
- unsigned int duplicated : 1;
- unsigned int opt_subexp : 1;
-#ifdef RE_ENABLE_I18N
- unsigned int accept_mb : 1;
- /* These 2 bits can be moved into the union if needed (e.g. if running out
- of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
- unsigned int mb_partial : 1;
-#endif
- unsigned int word_char : 1;
-} re_token_t;
-
-#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
-
-struct re_string_t
-{
- /* Indicate the raw buffer which is the original string passed as an
- argument of regexec(), re_search(), etc.. */
- const unsigned char *raw_mbs;
- /* Store the multibyte string. In case of "case insensitive mode" like
- REG_ICASE, upper cases of the string are stored, otherwise MBS points
- the same address that RAW_MBS points. */
- unsigned char *mbs;
-#ifdef RE_ENABLE_I18N
- /* Store the wide character string which is corresponding to MBS. */
- wint_t *wcs;
- Idx *offsets;
- mbstate_t cur_state;
-#endif
- /* Index in RAW_MBS. Each character mbs[i] corresponds to
- raw_mbs[raw_mbs_idx + i]. */
- Idx raw_mbs_idx;
- /* The length of the valid characters in the buffers. */
- Idx valid_len;
- /* The corresponding number of bytes in raw_mbs array. */
- Idx valid_raw_len;
- /* The length of the buffers MBS and WCS. */
- Idx bufs_len;
- /* The index in MBS, which is updated by re_string_fetch_byte. */
- Idx cur_idx;
- /* length of RAW_MBS array. */
- Idx raw_len;
- /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
- Idx len;
- /* End of the buffer may be shorter than its length in the cases such
- as re_match_2, re_search_2. Then, we use STOP for end of the buffer
- instead of LEN. */
- Idx raw_stop;
- /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
- Idx stop;
-
- /* The context of mbs[0]. We store the context independently, since
- the context of mbs[0] may be different from raw_mbs[0], which is
- the beginning of the input string. */
- unsigned int tip_context;
- /* The translation passed as a part of an argument of re_compile_pattern. */
- RE_TRANSLATE_TYPE trans;
- /* Copy of re_dfa_t's word_char. */
- re_const_bitset_ptr_t word_char;
- /* true if REG_ICASE. */
- unsigned char icase;
- unsigned char is_utf8;
- unsigned char map_notascii;
- unsigned char mbs_allocated;
- unsigned char offsets_needed;
- unsigned char newline_anchor;
- unsigned char word_ops_used;
- int mb_cur_max;
-};
-typedef struct re_string_t re_string_t;
-
-
-struct re_dfa_t;
-typedef struct re_dfa_t re_dfa_t;
-
-#ifndef _LIBC
-# define internal_function
-#endif
-
-#ifndef NOT_IN_libc
-static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
- Idx new_buf_len)
- internal_function;
-# ifdef RE_ENABLE_I18N
-static void build_wcs_buffer (re_string_t *pstr) internal_function;
-static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr)
- internal_function;
-# endif /* RE_ENABLE_I18N */
-static void build_upper_buffer (re_string_t *pstr) internal_function;
-static void re_string_translate_buffer (re_string_t *pstr) internal_function;
-static unsigned int re_string_context_at (const re_string_t *input, Idx idx,
- int eflags)
- internal_function __attribute__ ((pure));
-#endif
-#define re_string_peek_byte(pstr, offset) \
- ((pstr)->mbs[(pstr)->cur_idx + offset])
-#define re_string_fetch_byte(pstr) \
- ((pstr)->mbs[(pstr)->cur_idx++])
-#define re_string_first_byte(pstr, idx) \
- ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
-#define re_string_is_single_byte_char(pstr, idx) \
- ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
- || (pstr)->wcs[(idx) + 1] != WEOF))
-#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
-#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
-#define re_string_get_buffer(pstr) ((pstr)->mbs)
-#define re_string_length(pstr) ((pstr)->len)
-#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
-#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
-#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
-
-#if defined _LIBC || HAVE_ALLOCA
-# include "palloca.h"
-#endif
-
-#ifndef _LIBC
-# if HAVE_ALLOCA
-/* The OS usually guarantees only one guard page at the bottom of the stack,
- and a page size can be as small as 4096 bytes. So we cannot safely
- allocate anything larger than 4096 bytes. Also care for the possibility
- of a few compiler-allocated temporary stack slots. */
-# define __libc_use_alloca(n) ((n) < 4032)
-# else
-/* alloca is implemented with malloc, so just use malloc. */
-# define __libc_use_alloca(n) 0
-# undef alloca
-# define alloca(n) malloc (n)
-# endif
-#endif
-
-#ifdef _LIBC
-# define MALLOC_0_IS_NONNULL 1
-#elif !defined MALLOC_0_IS_NONNULL
-# define MALLOC_0_IS_NONNULL 0
-#endif
-
-#ifndef MAX
-# define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
-#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
-#define re_free(p) free (p)
-
-struct bin_tree_t
-{
- struct bin_tree_t *parent;
- struct bin_tree_t *left;
- struct bin_tree_t *right;
- struct bin_tree_t *first;
- struct bin_tree_t *next;
-
- re_token_t token;
-
- /* 'node_idx' is the index in dfa->nodes, if 'type' == 0.
- Otherwise 'type' indicate the type of this node. */
- Idx node_idx;
-};
-typedef struct bin_tree_t bin_tree_t;
-
-#define BIN_TREE_STORAGE_SIZE \
- ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
-
-struct bin_tree_storage_t
-{
- struct bin_tree_storage_t *next;
- bin_tree_t data[BIN_TREE_STORAGE_SIZE];
-};
-typedef struct bin_tree_storage_t bin_tree_storage_t;
-
-#define CONTEXT_WORD 1
-#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
-#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
-#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
-
-#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
-#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
-#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
-#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
-#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
-
-#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
-#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
-#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
-#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
-
-#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
- ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
- || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
- || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
- || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
-
-#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
- ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
- || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
- || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
- || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
-
-struct re_dfastate_t
-{
- re_hashval_t hash;
- re_node_set nodes;
- re_node_set non_eps_nodes;
- re_node_set inveclosure;
- re_node_set *entrance_nodes;
- struct re_dfastate_t **trtable, **word_trtable;
- unsigned int context : 4;
- unsigned int halt : 1;
- /* If this state can accept "multi byte".
- Note that we refer to multibyte characters, and multi character
- collating elements as "multi byte". */
- unsigned int accept_mb : 1;
- /* If this state has backreference node(s). */
- unsigned int has_backref : 1;
- unsigned int has_constraint : 1;
-};
-typedef struct re_dfastate_t re_dfastate_t;
-
-struct re_state_table_entry
-{
- Idx num;
- Idx alloc;
- re_dfastate_t **array;
-};
-
-/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
-
-typedef struct
-{
- Idx next_idx;
- Idx alloc;
- re_dfastate_t **array;
-} state_array_t;
-
-/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
-
-typedef struct
-{
- Idx node;
- Idx str_idx; /* The position NODE match at. */
- state_array_t path;
-} re_sub_match_last_t;
-
-/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
- And information about the node, whose type is OP_CLOSE_SUBEXP,
- corresponding to NODE is stored in LASTS. */
-
-typedef struct
-{
- Idx str_idx;
- Idx node;
- state_array_t *path;
- Idx alasts; /* Allocation size of LASTS. */
- Idx nlasts; /* The number of LASTS. */
- re_sub_match_last_t **lasts;
-} re_sub_match_top_t;
-
-struct re_backref_cache_entry
-{
- Idx node;
- Idx str_idx;
- Idx subexp_from;
- Idx subexp_to;
- char more;
- char unused;
- unsigned short int eps_reachable_subexps_map;
-};
-
-typedef struct
-{
- /* The string object corresponding to the input string. */
- re_string_t input;
-#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
- const re_dfa_t *const dfa;
-#else
- const re_dfa_t *dfa;
-#endif
- /* EFLAGS of the argument of regexec. */
- int eflags;
- /* Where the matching ends. */
- Idx match_last;
- Idx last_node;
- /* The state log used by the matcher. */
- re_dfastate_t **state_log;
- Idx state_log_top;
- /* Back reference cache. */
- Idx nbkref_ents;
- Idx abkref_ents;
- struct re_backref_cache_entry *bkref_ents;
- int max_mb_elem_len;
- Idx nsub_tops;
- Idx asub_tops;
- re_sub_match_top_t **sub_tops;
-} re_match_context_t;
-
-typedef struct
-{
- re_dfastate_t **sifted_states;
- re_dfastate_t **limited_states;
- Idx last_node;
- Idx last_str_idx;
- re_node_set limits;
-} re_sift_context_t;
-
-struct re_fail_stack_ent_t
-{
- Idx idx;
- Idx node;
- regmatch_t *regs;
- re_node_set eps_via_nodes;
-};
-
-struct re_fail_stack_t
-{
- Idx num;
- Idx alloc;
- struct re_fail_stack_ent_t *stack;
-};
-
-struct re_dfa_t
-{
- re_token_t *nodes;
- size_t nodes_alloc;
- size_t nodes_len;
- Idx *nexts;
- Idx *org_indices;
- re_node_set *edests;
- re_node_set *eclosures;
- re_node_set *inveclosures;
- struct re_state_table_entry *state_table;
- re_dfastate_t *init_state;
- re_dfastate_t *init_state_word;
- re_dfastate_t *init_state_nl;
- re_dfastate_t *init_state_begbuf;
- bin_tree_t *str_tree;
- bin_tree_storage_t *str_tree_storage;
- re_bitset_ptr_t sb_char;
- int str_tree_storage_idx;
-
- /* number of subexpressions 're_nsub' is in regex_t. */
- re_hashval_t state_hash_mask;
- Idx init_node;
- Idx nbackref; /* The number of backreference in this dfa. */
-
- /* Bitmap expressing which backreference is used. */
- bitset_word_t used_bkref_map;
- bitset_word_t completed_bkref_map;
-
- unsigned int has_plural_match : 1;
- /* If this dfa has "multibyte node", which is a backreference or
- a node which can accept multibyte character or multi character
- collating element. */
- unsigned int has_mb_node : 1;
- unsigned int is_utf8 : 1;
- unsigned int map_notascii : 1;
- unsigned int word_ops_used : 1;
- int mb_cur_max;
- bitset_t word_char;
- reg_syntax_t syntax;
- Idx *subexp_map;
-#ifdef DEBUG
- char* re_str;
-#endif
- lock_define (lock)
-};
-
-#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
-#define re_node_set_remove(set,id) \
- (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
-#define re_node_set_empty(p) ((p)->nelem = 0)
-#define re_node_set_free(set) re_free ((set)->elems)
-
-
-typedef enum
-{
- SB_CHAR,
- MB_CHAR,
- EQUIV_CLASS,
- COLL_SYM,
- CHAR_CLASS
-} bracket_elem_type;
-
-typedef struct
-{
- bracket_elem_type type;
- union
- {
- unsigned char ch;
- unsigned char *name;
- wchar_t wch;
- } opr;
-} bracket_elem_t;
-
-
-/* Functions for bitset_t operation. */
-
-static void
-bitset_set (bitset_t set, Idx i)
-{
- set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS;
-}
-
-static void
-bitset_clear (bitset_t set, Idx i)
-{
- set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS);
-}
-
-static bool
-bitset_contain (const bitset_t set, Idx i)
-{
- return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1;
-}
-
-static void
-bitset_empty (bitset_t set)
-{
- memset (set, '\0', sizeof (bitset_t));
-}
-
-static void
-bitset_set_all (bitset_t set)
-{
- memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS));
- if (SBC_MAX % BITSET_WORD_BITS != 0)
- set[BITSET_WORDS - 1] =
- ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1;
-}
-
-static void
-bitset_copy (bitset_t dest, const bitset_t src)
-{
- memcpy (dest, src, sizeof (bitset_t));
-}
-
-static void __attribute__ ((unused))
-bitset_not (bitset_t set)
-{
- int bitset_i;
- for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i)
- set[bitset_i] = ~set[bitset_i];
- if (SBC_MAX % BITSET_WORD_BITS != 0)
- set[BITSET_WORDS - 1] =
- ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1)
- & ~set[BITSET_WORDS - 1]);
-}
-
-static void __attribute__ ((unused))
-bitset_merge (bitset_t dest, const bitset_t src)
-{
- int bitset_i;
- for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
- dest[bitset_i] |= src[bitset_i];
-}
-
-static void __attribute__ ((unused))
-bitset_mask (bitset_t dest, const bitset_t src)
-{
- int bitset_i;
- for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
- dest[bitset_i] &= src[bitset_i];
-}
-
-#ifdef RE_ENABLE_I18N
-/* Functions for re_string. */
-static int
-internal_function __attribute__ ((pure, unused))
-re_string_char_size_at (const re_string_t *pstr, Idx idx)
-{
- int byte_idx;
- if (pstr->mb_cur_max == 1)
- return 1;
- for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
- if (pstr->wcs[idx + byte_idx] != WEOF)
- break;
- return byte_idx;
-}
-
-static wint_t
-internal_function __attribute__ ((pure, unused))
-re_string_wchar_at (const re_string_t *pstr, Idx idx)
-{
- if (pstr->mb_cur_max == 1)
- return (wint_t) pstr->mbs[idx];
- return (wint_t) pstr->wcs[idx];
-}
-
-# ifndef NOT_IN_libc
-static int
-internal_function __attribute__ ((pure, unused))
-re_string_elem_size_at (const re_string_t *pstr, Idx idx)
-{
-# ifdef _LIBC
- const unsigned char *p, *extra;
- const int32_t *table, *indirect;
-# include <locale/weight.h>
- uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
-
- if (nrules != 0)
- {
- table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
- extra = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
- indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
- _NL_COLLATE_INDIRECTMB);
- p = pstr->mbs + idx;
- findidx (&p, pstr->len - idx);
- return p - pstr->mbs - idx;
- }
- else
-# endif /* _LIBC */
- return 1;
-}
-# endif
-#endif /* RE_ENABLE_I18N */
-
-#ifndef __GNUC_PREREQ
-# if defined __GNUC__ && defined __GNUC_MINOR__
-# define __GNUC_PREREQ(maj, min) \
- ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-# else
-# define __GNUC_PREREQ(maj, min) 0
-# endif
-#endif
-
-#if __GNUC_PREREQ (3,4)
-# undef __attribute_warn_unused_result__
-# define __attribute_warn_unused_result__ \
- __attribute__ ((__warn_unused_result__))
-#else
-# define __attribute_warn_unused_result__ /* empty */
-#endif
-
-#endif /* _REGEX_INTERNAL_H */
diff --git a/contrib/tools/bison/lib/regexec.c b/contrib/tools/bison/lib/regexec.c
deleted file mode 100644
index d29d442baf..0000000000
--- a/contrib/tools/bison/lib/regexec.c
+++ /dev/null
@@ -1,4410 +0,0 @@
-/* Extended regular expression matching and search library.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
- Idx n) internal_function;
-static void match_ctx_clean (re_match_context_t *mctx) internal_function;
-static void match_ctx_free (re_match_context_t *cache) internal_function;
-static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, Idx node,
- Idx str_idx, Idx from, Idx to)
- internal_function;
-static Idx search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx)
- internal_function;
-static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, Idx node,
- Idx str_idx) internal_function;
-static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
- Idx node, Idx str_idx)
- internal_function;
-static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
- re_dfastate_t **limited_sts, Idx last_node,
- Idx last_str_idx)
- internal_function;
-static reg_errcode_t re_search_internal (const regex_t *preg,
- const char *string, Idx length,
- Idx start, Idx last_start, Idx stop,
- size_t nmatch, regmatch_t pmatch[],
- int eflags) internal_function;
-static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp,
- const char *string1, Idx length1,
- const char *string2, Idx length2,
- Idx start, regoff_t range,
- struct re_registers *regs,
- Idx stop, bool ret_len) internal_function;
-static regoff_t re_search_stub (struct re_pattern_buffer *bufp,
- const char *string, Idx length, Idx start,
- regoff_t range, Idx stop,
- struct re_registers *regs,
- bool ret_len) internal_function;
-static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
- Idx nregs, int regs_allocated) internal_function;
-static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
- internal_function;
-static Idx check_matching (re_match_context_t *mctx, bool fl_longest_match,
- Idx *p_match_first) internal_function;
-static Idx check_halt_state_context (const re_match_context_t *mctx,
- const re_dfastate_t *state, Idx idx)
- internal_function;
-static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
- regmatch_t *prev_idx_match, Idx cur_node,
- Idx cur_idx, Idx nmatch) internal_function;
-static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
- Idx str_idx, Idx dest_node, Idx nregs,
- regmatch_t *regs,
- re_node_set *eps_via_nodes)
- internal_function;
-static reg_errcode_t set_regs (const regex_t *preg,
- const re_match_context_t *mctx,
- size_t nmatch, regmatch_t *pmatch,
- bool fl_backtrack) internal_function;
-static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
- internal_function;
-
-#ifdef RE_ENABLE_I18N
-static int sift_states_iter_mb (const re_match_context_t *mctx,
- re_sift_context_t *sctx,
- Idx node_idx, Idx str_idx, Idx max_str_idx)
- internal_function;
-#endif /* RE_ENABLE_I18N */
-static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
- re_sift_context_t *sctx)
- internal_function;
-static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
- re_sift_context_t *sctx, Idx str_idx,
- re_node_set *cur_dest)
- internal_function;
-static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
- re_sift_context_t *sctx,
- Idx str_idx,
- re_node_set *dest_nodes)
- internal_function;
-static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
- re_node_set *dest_nodes,
- const re_node_set *candidates)
- internal_function;
-static bool check_dst_limits (const re_match_context_t *mctx,
- const re_node_set *limits,
- Idx dst_node, Idx dst_idx, Idx src_node,
- Idx src_idx) internal_function;
-static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
- int boundaries, Idx subexp_idx,
- Idx from_node, Idx bkref_idx)
- internal_function;
-static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
- Idx limit, Idx subexp_idx,
- Idx node, Idx str_idx,
- Idx bkref_idx) internal_function;
-static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
- re_node_set *dest_nodes,
- const re_node_set *candidates,
- re_node_set *limits,
- struct re_backref_cache_entry *bkref_ents,
- Idx str_idx) internal_function;
-static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
- re_sift_context_t *sctx,
- Idx str_idx, const re_node_set *candidates)
- internal_function;
-static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
- re_dfastate_t **dst,
- re_dfastate_t **src, Idx num)
- internal_function;
-static re_dfastate_t *find_recover_state (reg_errcode_t *err,
- re_match_context_t *mctx) internal_function;
-static re_dfastate_t *transit_state (reg_errcode_t *err,
- re_match_context_t *mctx,
- re_dfastate_t *state) internal_function;
-static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
- re_match_context_t *mctx,
- re_dfastate_t *next_state)
- internal_function;
-static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
- re_node_set *cur_nodes,
- Idx str_idx) internal_function;
-#if 0
-static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
- re_match_context_t *mctx,
- re_dfastate_t *pstate)
- internal_function;
-#endif
-#ifdef RE_ENABLE_I18N
-static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
- re_dfastate_t *pstate)
- internal_function;
-#endif /* RE_ENABLE_I18N */
-static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
- const re_node_set *nodes)
- internal_function;
-static reg_errcode_t get_subexp (re_match_context_t *mctx,
- Idx bkref_node, Idx bkref_str_idx)
- internal_function;
-static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
- const re_sub_match_top_t *sub_top,
- re_sub_match_last_t *sub_last,
- Idx bkref_node, Idx bkref_str)
- internal_function;
-static Idx find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
- Idx subexp_idx, int type) internal_function;
-static reg_errcode_t check_arrival (re_match_context_t *mctx,
- state_array_t *path, Idx top_node,
- Idx top_str, Idx last_node, Idx last_str,
- int type) internal_function;
-static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
- Idx str_idx,
- re_node_set *cur_nodes,
- re_node_set *next_nodes)
- internal_function;
-static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
- re_node_set *cur_nodes,
- Idx ex_subexp, int type)
- internal_function;
-static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
- re_node_set *dst_nodes,
- Idx target, Idx ex_subexp,
- int type) internal_function;
-static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
- re_node_set *cur_nodes, Idx cur_str,
- Idx subexp_num, int type)
- internal_function;
-static bool build_trtable (const re_dfa_t *dfa,
- re_dfastate_t *state) internal_function;
-#ifdef RE_ENABLE_I18N
-static int check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
- const re_string_t *input, Idx idx)
- internal_function;
-# ifdef _LIBC
-static unsigned int find_collation_sequence_value (const unsigned char *mbs,
- size_t name_len)
- internal_function;
-# endif /* _LIBC */
-#endif /* RE_ENABLE_I18N */
-static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa,
- const re_dfastate_t *state,
- re_node_set *states_node,
- bitset_t *states_ch) internal_function;
-static bool check_node_accept (const re_match_context_t *mctx,
- const re_token_t *node, Idx idx)
- internal_function;
-static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_len)
- internal_function;
-
-/* Entry point for POSIX code. */
-
-/* regexec searches for a given pattern, specified by PREG, in the
- string STRING.
-
- If NMATCH is zero or REG_NOSUB was set in the cflags argument to
- 'regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
- least NMATCH elements, and we set them to the offsets of the
- corresponding matched substrings.
-
- EFLAGS specifies "execution flags" which affect matching: if
- REG_NOTBOL is set, then ^ does not match at the beginning of the
- string; if REG_NOTEOL is set, then $ does not match at the end.
-
- We return 0 if we find a match and REG_NOMATCH if not. */
-
-int
-regexec (preg, string, nmatch, pmatch, eflags)
- const regex_t *_Restrict_ preg;
- const char *_Restrict_ string;
- size_t nmatch;
- regmatch_t pmatch[_Restrict_arr_];
- int eflags;
-{
- reg_errcode_t err;
- Idx start, length;
- re_dfa_t *dfa = preg->buffer;
-
- if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
- return REG_BADPAT;
-
- if (eflags & REG_STARTEND)
- {
- start = pmatch[0].rm_so;
- length = pmatch[0].rm_eo;
- }
- else
- {
- start = 0;
- length = strlen (string);
- }
-
- lock_lock (dfa->lock);
- if (preg->no_sub)
- err = re_search_internal (preg, string, length, start, length,
- length, 0, NULL, eflags);
- else
- err = re_search_internal (preg, string, length, start, length,
- length, nmatch, pmatch, eflags);
- lock_unlock (dfa->lock);
- return err != REG_NOERROR;
-}
-
-#ifdef _LIBC
-# include <shlib-compat.h>
-versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
-
-# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
-__typeof__ (__regexec) __compat_regexec;
-
-int
-attribute_compat_text_section
-__compat_regexec (const regex_t *_Restrict_ preg,
- const char *_Restrict_ string, size_t nmatch,
- regmatch_t pmatch[], int eflags)
-{
- return regexec (preg, string, nmatch, pmatch,
- eflags & (REG_NOTBOL | REG_NOTEOL));
-}
-compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
-# endif
-#endif
-
-/* Entry points for GNU code. */
-
-/* re_match, re_search, re_match_2, re_search_2
-
- The former two functions operate on STRING with length LENGTH,
- while the later two operate on concatenation of STRING1 and STRING2
- with lengths LENGTH1 and LENGTH2, respectively.
-
- re_match() matches the compiled pattern in BUFP against the string,
- starting at index START.
-
- re_search() first tries matching at index START, then it tries to match
- starting from index START + 1, and so on. The last start position tried
- is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
- way as re_match().)
-
- The parameter STOP of re_{match,search}_2 specifies that no match exceeding
- the first STOP characters of the concatenation of the strings should be
- concerned.
-
- If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
- and all groups is stored in REGS. (For the "_2" variants, the offsets are
- computed relative to the concatenation, not relative to the individual
- strings.)
-
- On success, re_match* functions return the length of the match, re_search*
- return the position of the start of the match. Return value -1 means no
- match was found and -2 indicates an internal error. */
-
-regoff_t
-re_match (bufp, string, length, start, regs)
- struct re_pattern_buffer *bufp;
- const char *string;
- Idx length, start;
- struct re_registers *regs;
-{
- return re_search_stub (bufp, string, length, start, 0, length, regs, true);
-}
-#ifdef _LIBC
-weak_alias (__re_match, re_match)
-#endif
-
-regoff_t
-re_search (bufp, string, length, start, range, regs)
- struct re_pattern_buffer *bufp;
- const char *string;
- Idx length, start;
- regoff_t range;
- struct re_registers *regs;
-{
- return re_search_stub (bufp, string, length, start, range, length, regs,
- false);
-}
-#ifdef _LIBC
-weak_alias (__re_search, re_search)
-#endif
-
-regoff_t
-re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop)
- struct re_pattern_buffer *bufp;
- const char *string1, *string2;
- Idx length1, length2, start, stop;
- struct re_registers *regs;
-{
- return re_search_2_stub (bufp, string1, length1, string2, length2,
- start, 0, regs, stop, true);
-}
-#ifdef _LIBC
-weak_alias (__re_match_2, re_match_2)
-#endif
-
-regoff_t
-re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop)
- struct re_pattern_buffer *bufp;
- const char *string1, *string2;
- Idx length1, length2, start, stop;
- regoff_t range;
- struct re_registers *regs;
-{
- return re_search_2_stub (bufp, string1, length1, string2, length2,
- start, range, regs, stop, false);
-}
-#ifdef _LIBC
-weak_alias (__re_search_2, re_search_2)
-#endif
-
-static regoff_t
-re_search_2_stub (struct re_pattern_buffer *bufp,
- const char *string1, Idx length1,
- const char *string2, Idx length2,
- Idx start, regoff_t range, struct re_registers *regs,
- Idx stop, bool ret_len)
-{
- const char *str;
- regoff_t rval;
- Idx len = length1 + length2;
- char *s = NULL;
-
- if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0))
- return -2;
-
- /* Concatenate the strings. */
- if (length2 > 0)
- if (length1 > 0)
- {
- s = re_malloc (char, len);
-
- if (BE (s == NULL, 0))
- return -2;
-#ifdef _LIBC
- memcpy (__mempcpy (s, string1, length1), string2, length2);
-#else
- memcpy (s, string1, length1);
- memcpy (s + length1, string2, length2);
-#endif
- str = s;
- }
- else
- str = string2;
- else
- str = string1;
-
- rval = re_search_stub (bufp, str, len, start, range, stop, regs,
- ret_len);
- re_free (s);
- return rval;
-}
-
-/* The parameters have the same meaning as those of re_search.
- Additional parameters:
- If RET_LEN is true the length of the match is returned (re_match style);
- otherwise the position of the match is returned. */
-
-static regoff_t
-re_search_stub (struct re_pattern_buffer *bufp,
- const char *string, Idx length,
- Idx start, regoff_t range, Idx stop, struct re_registers *regs,
- bool ret_len)
-{
- reg_errcode_t result;
- regmatch_t *pmatch;
- Idx nregs;
- regoff_t rval;
- int eflags = 0;
- re_dfa_t *dfa = bufp->buffer;
- Idx last_start = start + range;
-
- /* Check for out-of-range. */
- if (BE (start < 0 || start > length, 0))
- return -1;
- if (BE (length < last_start || (0 <= range && last_start < start), 0))
- last_start = length;
- else if (BE (last_start < 0 || (range < 0 && start <= last_start), 0))
- last_start = 0;
-
- lock_lock (dfa->lock);
-
- eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
- eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
-
- /* Compile fastmap if we haven't yet. */
- if (start < last_start && bufp->fastmap != NULL && !bufp->fastmap_accurate)
- re_compile_fastmap (bufp);
-
- if (BE (bufp->no_sub, 0))
- regs = NULL;
-
- /* We need at least 1 register. */
- if (regs == NULL)
- nregs = 1;
- else if (BE (bufp->regs_allocated == REGS_FIXED
- && regs->num_regs <= bufp->re_nsub, 0))
- {
- nregs = regs->num_regs;
- if (BE (nregs < 1, 0))
- {
- /* Nothing can be copied to regs. */
- regs = NULL;
- nregs = 1;
- }
- }
- else
- nregs = bufp->re_nsub + 1;
- pmatch = re_malloc (regmatch_t, nregs);
- if (BE (pmatch == NULL, 0))
- {
- rval = -2;
- goto out;
- }
-
- result = re_search_internal (bufp, string, length, start, last_start, stop,
- nregs, pmatch, eflags);
-
- rval = 0;
-
- /* I hope we needn't fill their regs with -1's when no match was found. */
- if (result != REG_NOERROR)
- rval = result == REG_NOMATCH ? -1 : -2;
- else if (regs != NULL)
- {
- /* If caller wants register contents data back, copy them. */
- bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
- bufp->regs_allocated);
- if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
- rval = -2;
- }
-
- if (BE (rval == 0, 1))
- {
- if (ret_len)
- {
- assert (pmatch[0].rm_so == start);
- rval = pmatch[0].rm_eo - start;
- }
- else
- rval = pmatch[0].rm_so;
- }
- re_free (pmatch);
- out:
- lock_unlock (dfa->lock);
- return rval;
-}
-
-static unsigned
-re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs,
- int regs_allocated)
-{
- int rval = REGS_REALLOCATE;
- Idx i;
- Idx need_regs = nregs + 1;
- /* We need one extra element beyond 'num_regs' for the '-1' marker GNU code
- uses. */
-
- /* Have the register data arrays been allocated? */
- if (regs_allocated == REGS_UNALLOCATED)
- { /* No. So allocate them with malloc. */
- regs->start = re_malloc (regoff_t, need_regs);
- if (BE (regs->start == NULL, 0))
- return REGS_UNALLOCATED;
- regs->end = re_malloc (regoff_t, need_regs);
- if (BE (regs->end == NULL, 0))
- {
- re_free (regs->start);
- return REGS_UNALLOCATED;
- }
- regs->num_regs = need_regs;
- }
- else if (regs_allocated == REGS_REALLOCATE)
- { /* Yes. If we need more elements than were already
- allocated, reallocate them. If we need fewer, just
- leave it alone. */
- if (BE (need_regs > regs->num_regs, 0))
- {
- regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
- regoff_t *new_end;
- if (BE (new_start == NULL, 0))
- return REGS_UNALLOCATED;
- new_end = re_realloc (regs->end, regoff_t, need_regs);
- if (BE (new_end == NULL, 0))
- {
- re_free (new_start);
- return REGS_UNALLOCATED;
- }
- regs->start = new_start;
- regs->end = new_end;
- regs->num_regs = need_regs;
- }
- }
- else
- {
- assert (regs_allocated == REGS_FIXED);
- /* This function may not be called with REGS_FIXED and nregs too big. */
- assert (regs->num_regs >= nregs);
- rval = REGS_FIXED;
- }
-
- /* Copy the regs. */
- for (i = 0; i < nregs; ++i)
- {
- regs->start[i] = pmatch[i].rm_so;
- regs->end[i] = pmatch[i].rm_eo;
- }
- for ( ; i < regs->num_regs; ++i)
- regs->start[i] = regs->end[i] = -1;
-
- return rval;
-}
-
-/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
- ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
- this memory for recording register information. STARTS and ENDS
- must be allocated using the malloc library routine, and must each
- be at least NUM_REGS * sizeof (regoff_t) bytes long.
-
- If NUM_REGS == 0, then subsequent matches should allocate their own
- register data.
-
- Unless this function is called, the first search or match using
- PATTERN_BUFFER will allocate its own register data, without
- freeing the old data. */
-
-void
-re_set_registers (bufp, regs, num_regs, starts, ends)
- struct re_pattern_buffer *bufp;
- struct re_registers *regs;
- __re_size_t num_regs;
- regoff_t *starts, *ends;
-{
- if (num_regs)
- {
- bufp->regs_allocated = REGS_REALLOCATE;
- regs->num_regs = num_regs;
- regs->start = starts;
- regs->end = ends;
- }
- else
- {
- bufp->regs_allocated = REGS_UNALLOCATED;
- regs->num_regs = 0;
- regs->start = regs->end = NULL;
- }
-}
-#ifdef _LIBC
-weak_alias (__re_set_registers, re_set_registers)
-#endif
-
-/* Entry points compatible with 4.2 BSD regex library. We don't define
- them unless specifically requested. */
-
-#if defined _REGEX_RE_COMP || defined _LIBC
-int
-# ifdef _LIBC
-weak_function
-# endif
-re_exec (s)
- const char *s;
-{
- return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
-}
-#endif /* _REGEX_RE_COMP */
-
-/* Internal entry point. */
-
-/* Searches for a compiled pattern PREG in the string STRING, whose
- length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
- meaning as with regexec. LAST_START is START + RANGE, where
- START and RANGE have the same meaning as with re_search.
- Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
- otherwise return the error code.
- Note: We assume front end functions already check ranges.
- (0 <= LAST_START && LAST_START <= LENGTH) */
-
-static reg_errcode_t
-__attribute_warn_unused_result__
-re_search_internal (const regex_t *preg,
- const char *string, Idx length,
- Idx start, Idx last_start, Idx stop,
- size_t nmatch, regmatch_t pmatch[],
- int eflags)
-{
- reg_errcode_t err;
- const re_dfa_t *dfa = preg->buffer;
- Idx left_lim, right_lim;
- int incr;
- bool fl_longest_match;
- int match_kind;
- Idx match_first;
- Idx match_last = REG_MISSING;
- Idx extra_nmatch;
- bool sb;
- int ch;
-#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
- re_match_context_t mctx = { .dfa = dfa };
-#else
- re_match_context_t mctx;
-#endif
- char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate
- && start != last_start && !preg->can_be_null)
- ? preg->fastmap : NULL);
- RE_TRANSLATE_TYPE t = preg->translate;
-
-#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
- memset (&mctx, '\0', sizeof (re_match_context_t));
- mctx.dfa = dfa;
-#endif
-
- extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
- nmatch -= extra_nmatch;
-
- /* Check if the DFA haven't been compiled. */
- if (BE (preg->used == 0 || dfa->init_state == NULL
- || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
- || dfa->init_state_begbuf == NULL, 0))
- return REG_NOMATCH;
-
-#ifdef DEBUG
- /* We assume front-end functions already check them. */
- assert (0 <= last_start && last_start <= length);
-#endif
-
- /* If initial states with non-begbuf contexts have no elements,
- the regex must be anchored. If preg->newline_anchor is set,
- we'll never use init_state_nl, so do not check it. */
- if (dfa->init_state->nodes.nelem == 0
- && dfa->init_state_word->nodes.nelem == 0
- && (dfa->init_state_nl->nodes.nelem == 0
- || !preg->newline_anchor))
- {
- if (start != 0 && last_start != 0)
- return REG_NOMATCH;
- start = last_start = 0;
- }
-
- /* We must check the longest matching, if nmatch > 0. */
- fl_longest_match = (nmatch != 0 || dfa->nbackref);
-
- err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
- preg->translate, (preg->syntax & RE_ICASE) != 0,
- dfa);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- mctx.input.stop = stop;
- mctx.input.raw_stop = stop;
- mctx.input.newline_anchor = preg->newline_anchor;
-
- err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
-
- /* We will log all the DFA states through which the dfa pass,
- if nmatch > 1, or this dfa has "multibyte node", which is a
- back-reference or a node which can accept multibyte character or
- multi character collating element. */
- if (nmatch > 1 || dfa->has_mb_node)
- {
- /* Avoid overflow. */
- if (BE ((MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *))
- <= mctx.input.bufs_len), 0))
- {
- err = REG_ESPACE;
- goto free_return;
- }
-
- mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
- if (BE (mctx.state_log == NULL, 0))
- {
- err = REG_ESPACE;
- goto free_return;
- }
- }
- else
- mctx.state_log = NULL;
-
- match_first = start;
- mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
- : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
-
- /* Check incrementally whether the input string matches. */
- incr = (last_start < start) ? -1 : 1;
- left_lim = (last_start < start) ? last_start : start;
- right_lim = (last_start < start) ? start : last_start;
- sb = dfa->mb_cur_max == 1;
- match_kind =
- (fastmap
- ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
- | (start <= last_start ? 2 : 0)
- | (t != NULL ? 1 : 0))
- : 8);
-
- for (;; match_first += incr)
- {
- err = REG_NOMATCH;
- if (match_first < left_lim || right_lim < match_first)
- goto free_return;
-
- /* Advance as rapidly as possible through the string, until we
- find a plausible place to start matching. This may be done
- with varying efficiency, so there are various possibilities:
- only the most common of them are specialized, in order to
- save on code size. We use a switch statement for speed. */
- switch (match_kind)
- {
- case 8:
- /* No fastmap. */
- break;
-
- case 7:
- /* Fastmap with single-byte translation, match forward. */
- while (BE (match_first < right_lim, 1)
- && !fastmap[t[(unsigned char) string[match_first]]])
- ++match_first;
- goto forward_match_found_start_or_reached_end;
-
- case 6:
- /* Fastmap without translation, match forward. */
- while (BE (match_first < right_lim, 1)
- && !fastmap[(unsigned char) string[match_first]])
- ++match_first;
-
- forward_match_found_start_or_reached_end:
- if (BE (match_first == right_lim, 0))
- {
- ch = match_first >= length
- ? 0 : (unsigned char) string[match_first];
- if (!fastmap[t ? t[ch] : ch])
- goto free_return;
- }
- break;
-
- case 4:
- case 5:
- /* Fastmap without multi-byte translation, match backwards. */
- while (match_first >= left_lim)
- {
- ch = match_first >= length
- ? 0 : (unsigned char) string[match_first];
- if (fastmap[t ? t[ch] : ch])
- break;
- --match_first;
- }
- if (match_first < left_lim)
- goto free_return;
- break;
-
- default:
- /* In this case, we can't determine easily the current byte,
- since it might be a component byte of a multibyte
- character. Then we use the constructed buffer instead. */
- for (;;)
- {
- /* If MATCH_FIRST is out of the valid range, reconstruct the
- buffers. */
- __re_size_t offset = match_first - mctx.input.raw_mbs_idx;
- if (BE (offset >= (__re_size_t) mctx.input.valid_raw_len, 0))
- {
- err = re_string_reconstruct (&mctx.input, match_first,
- eflags);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
-
- offset = match_first - mctx.input.raw_mbs_idx;
- }
- /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
- Note that MATCH_FIRST must not be smaller than 0. */
- ch = (match_first >= length
- ? 0 : re_string_byte_at (&mctx.input, offset));
- if (fastmap[ch])
- break;
- match_first += incr;
- if (match_first < left_lim || match_first > right_lim)
- {
- err = REG_NOMATCH;
- goto free_return;
- }
- }
- break;
- }
-
- /* Reconstruct the buffers so that the matcher can assume that
- the matching starts from the beginning of the buffer. */
- err = re_string_reconstruct (&mctx.input, match_first, eflags);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
-
-#ifdef RE_ENABLE_I18N
- /* Don't consider this char as a possible match start if it part,
- yet isn't the head, of a multibyte character. */
- if (!sb && !re_string_first_byte (&mctx.input, 0))
- continue;
-#endif
-
- /* It seems to be appropriate one, then use the matcher. */
- /* We assume that the matching starts from 0. */
- mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
- match_last = check_matching (&mctx, fl_longest_match,
- start <= last_start ? &match_first : NULL);
- if (match_last != REG_MISSING)
- {
- if (BE (match_last == REG_ERROR, 0))
- {
- err = REG_ESPACE;
- goto free_return;
- }
- else
- {
- mctx.match_last = match_last;
- if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
- {
- re_dfastate_t *pstate = mctx.state_log[match_last];
- mctx.last_node = check_halt_state_context (&mctx, pstate,
- match_last);
- }
- if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
- || dfa->nbackref)
- {
- err = prune_impossible_nodes (&mctx);
- if (err == REG_NOERROR)
- break;
- if (BE (err != REG_NOMATCH, 0))
- goto free_return;
- match_last = REG_MISSING;
- }
- else
- break; /* We found a match. */
- }
- }
-
- match_ctx_clean (&mctx);
- }
-
-#ifdef DEBUG
- assert (match_last != REG_MISSING);
- assert (err == REG_NOERROR);
-#endif
-
- /* Set pmatch[] if we need. */
- if (nmatch > 0)
- {
- Idx reg_idx;
-
- /* Initialize registers. */
- for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
- pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
-
- /* Set the points where matching start/end. */
- pmatch[0].rm_so = 0;
- pmatch[0].rm_eo = mctx.match_last;
- /* FIXME: This function should fail if mctx.match_last exceeds
- the maximum possible regoff_t value. We need a new error
- code REG_OVERFLOW. */
-
- if (!preg->no_sub && nmatch > 1)
- {
- err = set_regs (preg, &mctx, nmatch, pmatch,
- dfa->has_plural_match && dfa->nbackref > 0);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
-
- /* At last, add the offset to each register, since we slid
- the buffers so that we could assume that the matching starts
- from 0. */
- for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
- if (pmatch[reg_idx].rm_so != -1)
- {
-#ifdef RE_ENABLE_I18N
- if (BE (mctx.input.offsets_needed != 0, 0))
- {
- pmatch[reg_idx].rm_so =
- (pmatch[reg_idx].rm_so == mctx.input.valid_len
- ? mctx.input.valid_raw_len
- : mctx.input.offsets[pmatch[reg_idx].rm_so]);
- pmatch[reg_idx].rm_eo =
- (pmatch[reg_idx].rm_eo == mctx.input.valid_len
- ? mctx.input.valid_raw_len
- : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
- }
-#else
- assert (mctx.input.offsets_needed == 0);
-#endif
- pmatch[reg_idx].rm_so += match_first;
- pmatch[reg_idx].rm_eo += match_first;
- }
- for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
- {
- pmatch[nmatch + reg_idx].rm_so = -1;
- pmatch[nmatch + reg_idx].rm_eo = -1;
- }
-
- if (dfa->subexp_map)
- for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
- if (dfa->subexp_map[reg_idx] != reg_idx)
- {
- pmatch[reg_idx + 1].rm_so
- = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
- pmatch[reg_idx + 1].rm_eo
- = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
- }
- }
-
- free_return:
- re_free (mctx.state_log);
- if (dfa->nbackref)
- match_ctx_free (&mctx);
- re_string_destruct (&mctx.input);
- return err;
-}
-
-static reg_errcode_t
-__attribute_warn_unused_result__
-prune_impossible_nodes (re_match_context_t *mctx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx halt_node, match_last;
- reg_errcode_t ret;
- re_dfastate_t **sifted_states;
- re_dfastate_t **lim_states = NULL;
- re_sift_context_t sctx;
-#ifdef DEBUG
- assert (mctx->state_log != NULL);
-#endif
- match_last = mctx->match_last;
- halt_node = mctx->last_node;
-
- /* Avoid overflow. */
- if (BE (MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *)) <= match_last, 0))
- return REG_ESPACE;
-
- sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
- if (BE (sifted_states == NULL, 0))
- {
- ret = REG_ESPACE;
- goto free_return;
- }
- if (dfa->nbackref)
- {
- lim_states = re_malloc (re_dfastate_t *, match_last + 1);
- if (BE (lim_states == NULL, 0))
- {
- ret = REG_ESPACE;
- goto free_return;
- }
- while (1)
- {
- memset (lim_states, '\0',
- sizeof (re_dfastate_t *) * (match_last + 1));
- sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
- match_last);
- ret = sift_states_backward (mctx, &sctx);
- re_node_set_free (&sctx.limits);
- if (BE (ret != REG_NOERROR, 0))
- goto free_return;
- if (sifted_states[0] != NULL || lim_states[0] != NULL)
- break;
- do
- {
- --match_last;
- if (! REG_VALID_INDEX (match_last))
- {
- ret = REG_NOMATCH;
- goto free_return;
- }
- } while (mctx->state_log[match_last] == NULL
- || !mctx->state_log[match_last]->halt);
- halt_node = check_halt_state_context (mctx,
- mctx->state_log[match_last],
- match_last);
- }
- ret = merge_state_array (dfa, sifted_states, lim_states,
- match_last + 1);
- re_free (lim_states);
- lim_states = NULL;
- if (BE (ret != REG_NOERROR, 0))
- goto free_return;
- }
- else
- {
- sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
- ret = sift_states_backward (mctx, &sctx);
- re_node_set_free (&sctx.limits);
- if (BE (ret != REG_NOERROR, 0))
- goto free_return;
- if (sifted_states[0] == NULL)
- {
- ret = REG_NOMATCH;
- goto free_return;
- }
- }
- re_free (mctx->state_log);
- mctx->state_log = sifted_states;
- sifted_states = NULL;
- mctx->last_node = halt_node;
- mctx->match_last = match_last;
- ret = REG_NOERROR;
- free_return:
- re_free (sifted_states);
- re_free (lim_states);
- return ret;
-}
-
-/* Acquire an initial state and return it.
- We must select appropriate initial state depending on the context,
- since initial states may have constraints like "\<", "^", etc.. */
-
-static inline re_dfastate_t *
-__attribute__ ((always_inline)) internal_function
-acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
- Idx idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- if (dfa->init_state->has_constraint)
- {
- unsigned int context;
- context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
- if (IS_WORD_CONTEXT (context))
- return dfa->init_state_word;
- else if (IS_ORDINARY_CONTEXT (context))
- return dfa->init_state;
- else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
- return dfa->init_state_begbuf;
- else if (IS_NEWLINE_CONTEXT (context))
- return dfa->init_state_nl;
- else if (IS_BEGBUF_CONTEXT (context))
- {
- /* It is relatively rare case, then calculate on demand. */
- return re_acquire_state_context (err, dfa,
- dfa->init_state->entrance_nodes,
- context);
- }
- else
- /* Must not happen? */
- return dfa->init_state;
- }
- else
- return dfa->init_state;
-}
-
-/* Check whether the regular expression match input string INPUT or not,
- and return the index where the matching end. Return REG_MISSING if
- there is no match, and return REG_ERROR in case of an error.
- FL_LONGEST_MATCH means we want the POSIX longest matching.
- If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
- next place where we may want to try matching.
- Note that the matcher assumes that the matching starts from the current
- index of the buffer. */
-
-static Idx
-internal_function __attribute_warn_unused_result__
-check_matching (re_match_context_t *mctx, bool fl_longest_match,
- Idx *p_match_first)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err;
- Idx match = 0;
- Idx match_last = REG_MISSING;
- Idx cur_str_idx = re_string_cur_idx (&mctx->input);
- re_dfastate_t *cur_state;
- bool at_init_state = p_match_first != NULL;
- Idx next_start_idx = cur_str_idx;
-
- err = REG_NOERROR;
- cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
- /* An initial state must not be NULL (invalid). */
- if (BE (cur_state == NULL, 0))
- {
- assert (err == REG_ESPACE);
- return REG_ERROR;
- }
-
- if (mctx->state_log != NULL)
- {
- mctx->state_log[cur_str_idx] = cur_state;
-
- /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
- later. E.g. Processing back references. */
- if (BE (dfa->nbackref, 0))
- {
- at_init_state = false;
- err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- if (cur_state->has_backref)
- {
- err = transit_state_bkref (mctx, &cur_state->nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- }
- }
-
- /* If the RE accepts NULL string. */
- if (BE (cur_state->halt, 0))
- {
- if (!cur_state->has_constraint
- || check_halt_state_context (mctx, cur_state, cur_str_idx))
- {
- if (!fl_longest_match)
- return cur_str_idx;
- else
- {
- match_last = cur_str_idx;
- match = 1;
- }
- }
- }
-
- while (!re_string_eoi (&mctx->input))
- {
- re_dfastate_t *old_state = cur_state;
- Idx next_char_idx = re_string_cur_idx (&mctx->input) + 1;
-
- if ((BE (next_char_idx >= mctx->input.bufs_len, 0)
- && mctx->input.bufs_len < mctx->input.len)
- || (BE (next_char_idx >= mctx->input.valid_len, 0)
- && mctx->input.valid_len < mctx->input.len))
- {
- err = extend_buffers (mctx, next_char_idx + 1);
- if (BE (err != REG_NOERROR, 0))
- {
- assert (err == REG_ESPACE);
- return REG_ERROR;
- }
- }
-
- cur_state = transit_state (&err, mctx, cur_state);
- if (mctx->state_log != NULL)
- cur_state = merge_state_with_log (&err, mctx, cur_state);
-
- if (cur_state == NULL)
- {
- /* Reached the invalid state or an error. Try to recover a valid
- state using the state log, if available and if we have not
- already found a valid (even if not the longest) match. */
- if (BE (err != REG_NOERROR, 0))
- return REG_ERROR;
-
- if (mctx->state_log == NULL
- || (match && !fl_longest_match)
- || (cur_state = find_recover_state (&err, mctx)) == NULL)
- break;
- }
-
- if (BE (at_init_state, 0))
- {
- if (old_state == cur_state)
- next_start_idx = next_char_idx;
- else
- at_init_state = false;
- }
-
- if (cur_state->halt)
- {
- /* Reached a halt state.
- Check the halt state can satisfy the current context. */
- if (!cur_state->has_constraint
- || check_halt_state_context (mctx, cur_state,
- re_string_cur_idx (&mctx->input)))
- {
- /* We found an appropriate halt state. */
- match_last = re_string_cur_idx (&mctx->input);
- match = 1;
-
- /* We found a match, do not modify match_first below. */
- p_match_first = NULL;
- if (!fl_longest_match)
- break;
- }
- }
- }
-
- if (p_match_first)
- *p_match_first += next_start_idx;
-
- return match_last;
-}
-
-/* Check NODE match the current context. */
-
-static bool
-internal_function
-check_halt_node_context (const re_dfa_t *dfa, Idx node, unsigned int context)
-{
- re_token_type_t type = dfa->nodes[node].type;
- unsigned int constraint = dfa->nodes[node].constraint;
- if (type != END_OF_RE)
- return false;
- if (!constraint)
- return true;
- if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
- return false;
- return true;
-}
-
-/* Check the halt state STATE match the current context.
- Return 0 if not match, if the node, STATE has, is a halt node and
- match the context, return the node. */
-
-static Idx
-internal_function
-check_halt_state_context (const re_match_context_t *mctx,
- const re_dfastate_t *state, Idx idx)
-{
- Idx i;
- unsigned int context;
-#ifdef DEBUG
- assert (state->halt);
-#endif
- context = re_string_context_at (&mctx->input, idx, mctx->eflags);
- for (i = 0; i < state->nodes.nelem; ++i)
- if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
- return state->nodes.elems[i];
- return 0;
-}
-
-/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
- corresponding to the DFA).
- Return the destination node, and update EPS_VIA_NODES;
- return REG_MISSING in case of errors. */
-
-static Idx
-internal_function
-proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
- Idx *pidx, Idx node, re_node_set *eps_via_nodes,
- struct re_fail_stack_t *fs)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx i;
- bool ok;
- if (IS_EPSILON_NODE (dfa->nodes[node].type))
- {
- re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
- re_node_set *edests = &dfa->edests[node];
- Idx dest_node;
- ok = re_node_set_insert (eps_via_nodes, node);
- if (BE (! ok, 0))
- return REG_ERROR;
- /* Pick up a valid destination, or return REG_MISSING if none
- is found. */
- for (dest_node = REG_MISSING, i = 0; i < edests->nelem; ++i)
- {
- Idx candidate = edests->elems[i];
- if (!re_node_set_contains (cur_nodes, candidate))
- continue;
- if (dest_node == REG_MISSING)
- dest_node = candidate;
-
- else
- {
- /* In order to avoid infinite loop like "(a*)*", return the second
- epsilon-transition if the first was already considered. */
- if (re_node_set_contains (eps_via_nodes, dest_node))
- return candidate;
-
- /* Otherwise, push the second epsilon-transition on the fail stack. */
- else if (fs != NULL
- && push_fail_stack (fs, *pidx, candidate, nregs, regs,
- eps_via_nodes))
- return REG_ERROR;
-
- /* We know we are going to exit. */
- break;
- }
- }
- return dest_node;
- }
- else
- {
- Idx naccepted = 0;
- re_token_type_t type = dfa->nodes[node].type;
-
-#ifdef RE_ENABLE_I18N
- if (dfa->nodes[node].accept_mb)
- naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
- else
-#endif /* RE_ENABLE_I18N */
- if (type == OP_BACK_REF)
- {
- Idx subexp_idx = dfa->nodes[node].opr.idx + 1;
- naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
- if (fs != NULL)
- {
- if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
- return REG_MISSING;
- else if (naccepted)
- {
- char *buf = (char *) re_string_get_buffer (&mctx->input);
- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
- naccepted) != 0)
- return REG_MISSING;
- }
- }
-
- if (naccepted == 0)
- {
- Idx dest_node;
- ok = re_node_set_insert (eps_via_nodes, node);
- if (BE (! ok, 0))
- return REG_ERROR;
- dest_node = dfa->edests[node].elems[0];
- if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
- dest_node))
- return dest_node;
- }
- }
-
- if (naccepted != 0
- || check_node_accept (mctx, dfa->nodes + node, *pidx))
- {
- Idx dest_node = dfa->nexts[node];
- *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
- if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
- || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
- dest_node)))
- return REG_MISSING;
- re_node_set_empty (eps_via_nodes);
- return dest_node;
- }
- }
- return REG_MISSING;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node,
- Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
-{
- reg_errcode_t err;
- Idx num = fs->num++;
- if (fs->num == fs->alloc)
- {
- struct re_fail_stack_ent_t *new_array;
- new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
- * fs->alloc * 2));
- if (new_array == NULL)
- return REG_ESPACE;
- fs->alloc *= 2;
- fs->stack = new_array;
- }
- fs->stack[num].idx = str_idx;
- fs->stack[num].node = dest_node;
- fs->stack[num].regs = re_malloc (regmatch_t, nregs);
- if (fs->stack[num].regs == NULL)
- return REG_ESPACE;
- memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
- err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
- return err;
-}
-
-static Idx
-internal_function
-pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs,
- regmatch_t *regs, re_node_set *eps_via_nodes)
-{
- Idx num = --fs->num;
- assert (REG_VALID_INDEX (num));
- *pidx = fs->stack[num].idx;
- memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
- re_node_set_free (eps_via_nodes);
- re_free (fs->stack[num].regs);
- *eps_via_nodes = fs->stack[num].eps_via_nodes;
- return fs->stack[num].node;
-}
-
-/* Set the positions where the subexpressions are starts/ends to registers
- PMATCH.
- Note: We assume that pmatch[0] is already set, and
- pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
- regmatch_t *pmatch, bool fl_backtrack)
-{
- const re_dfa_t *dfa = preg->buffer;
- Idx idx, cur_node;
- re_node_set eps_via_nodes;
- struct re_fail_stack_t *fs;
- struct re_fail_stack_t fs_body = { 0, 2, NULL };
- regmatch_t *prev_idx_match;
- bool prev_idx_match_malloced = false;
-
-#ifdef DEBUG
- assert (nmatch > 1);
- assert (mctx->state_log != NULL);
-#endif
- if (fl_backtrack)
- {
- fs = &fs_body;
- fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
- if (fs->stack == NULL)
- return REG_ESPACE;
- }
- else
- fs = NULL;
-
- cur_node = dfa->init_node;
- re_node_set_init_empty (&eps_via_nodes);
-
- if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
- prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
- else
- {
- prev_idx_match = re_malloc (regmatch_t, nmatch);
- if (prev_idx_match == NULL)
- {
- free_fail_stack_return (fs);
- return REG_ESPACE;
- }
- prev_idx_match_malloced = true;
- }
- memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
-
- for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
- {
- update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
-
- if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
- {
- Idx reg_idx;
- if (fs)
- {
- for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
- if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
- break;
- if (reg_idx == nmatch)
- {
- re_node_set_free (&eps_via_nodes);
- if (prev_idx_match_malloced)
- re_free (prev_idx_match);
- return free_fail_stack_return (fs);
- }
- cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
- &eps_via_nodes);
- }
- else
- {
- re_node_set_free (&eps_via_nodes);
- if (prev_idx_match_malloced)
- re_free (prev_idx_match);
- return REG_NOERROR;
- }
- }
-
- /* Proceed to next node. */
- cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
- &eps_via_nodes, fs);
-
- if (BE (! REG_VALID_INDEX (cur_node), 0))
- {
- if (BE (cur_node == REG_ERROR, 0))
- {
- re_node_set_free (&eps_via_nodes);
- if (prev_idx_match_malloced)
- re_free (prev_idx_match);
- free_fail_stack_return (fs);
- return REG_ESPACE;
- }
- if (fs)
- cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
- &eps_via_nodes);
- else
- {
- re_node_set_free (&eps_via_nodes);
- if (prev_idx_match_malloced)
- re_free (prev_idx_match);
- return REG_NOMATCH;
- }
- }
- }
- re_node_set_free (&eps_via_nodes);
- if (prev_idx_match_malloced)
- re_free (prev_idx_match);
- return free_fail_stack_return (fs);
-}
-
-static reg_errcode_t
-internal_function
-free_fail_stack_return (struct re_fail_stack_t *fs)
-{
- if (fs)
- {
- Idx fs_idx;
- for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
- {
- re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
- re_free (fs->stack[fs_idx].regs);
- }
- re_free (fs->stack);
- }
- return REG_NOERROR;
-}
-
-static void
-internal_function
-update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
- regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch)
-{
- int type = dfa->nodes[cur_node].type;
- if (type == OP_OPEN_SUBEXP)
- {
- Idx reg_num = dfa->nodes[cur_node].opr.idx + 1;
-
- /* We are at the first node of this sub expression. */
- if (reg_num < nmatch)
- {
- pmatch[reg_num].rm_so = cur_idx;
- pmatch[reg_num].rm_eo = -1;
- }
- }
- else if (type == OP_CLOSE_SUBEXP)
- {
- Idx reg_num = dfa->nodes[cur_node].opr.idx + 1;
- if (reg_num < nmatch)
- {
- /* We are at the last node of this sub expression. */
- if (pmatch[reg_num].rm_so < cur_idx)
- {
- pmatch[reg_num].rm_eo = cur_idx;
- /* This is a non-empty match or we are not inside an optional
- subexpression. Accept this right away. */
- memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
- }
- else
- {
- if (dfa->nodes[cur_node].opt_subexp
- && prev_idx_match[reg_num].rm_so != -1)
- /* We transited through an empty match for an optional
- subexpression, like (a?)*, and this is not the subexp's
- first match. Copy back the old content of the registers
- so that matches of an inner subexpression are undone as
- well, like in ((a?))*. */
- memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
- else
- /* We completed a subexpression, but it may be part of
- an optional one, so do not update PREV_IDX_MATCH. */
- pmatch[reg_num].rm_eo = cur_idx;
- }
- }
- }
-}
-
-/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
- and sift the nodes in each states according to the following rules.
- Updated state_log will be wrote to STATE_LOG.
-
- Rules: We throw away the Node 'a' in the STATE_LOG[STR_IDX] if...
- 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
- If 'a' isn't the LAST_NODE and 'a' can't epsilon transit to
- the LAST_NODE, we throw away the node 'a'.
- 2. When 0 <= STR_IDX < MATCH_LAST and 'a' accepts
- string 's' and transit to 'b':
- i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
- away the node 'a'.
- ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
- thrown away, we throw away the node 'a'.
- 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
- i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
- node 'a'.
- ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
- we throw away the node 'a'. */
-
-#define STATE_NODE_CONTAINS(state,node) \
- ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
-
-static reg_errcode_t
-internal_function
-sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
-{
- reg_errcode_t err;
- int null_cnt = 0;
- Idx str_idx = sctx->last_str_idx;
- re_node_set cur_dest;
-
-#ifdef DEBUG
- assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
-#endif
-
- /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
- transit to the last_node and the last_node itself. */
- err = re_node_set_init_1 (&cur_dest, sctx->last_node);
- if (BE (err != REG_NOERROR, 0))
- return err;
- err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
-
- /* Then check each states in the state_log. */
- while (str_idx > 0)
- {
- /* Update counters. */
- null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
- if (null_cnt > mctx->max_mb_elem_len)
- {
- memset (sctx->sifted_states, '\0',
- sizeof (re_dfastate_t *) * str_idx);
- re_node_set_free (&cur_dest);
- return REG_NOERROR;
- }
- re_node_set_empty (&cur_dest);
- --str_idx;
-
- if (mctx->state_log[str_idx])
- {
- err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
-
- /* Add all the nodes which satisfy the following conditions:
- - It can epsilon transit to a node in CUR_DEST.
- - It is in CUR_SRC.
- And update state_log. */
- err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
- err = REG_NOERROR;
- free_return:
- re_node_set_free (&cur_dest);
- return err;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
- Idx str_idx, re_node_set *cur_dest)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
- Idx i;
-
- /* Then build the next sifted state.
- We build the next sifted state on 'cur_dest', and update
- 'sifted_states[str_idx]' with 'cur_dest'.
- Note:
- 'cur_dest' is the sifted state from 'state_log[str_idx + 1]'.
- 'cur_src' points the node_set of the old 'state_log[str_idx]'
- (with the epsilon nodes pre-filtered out). */
- for (i = 0; i < cur_src->nelem; i++)
- {
- Idx prev_node = cur_src->elems[i];
- int naccepted = 0;
- bool ok;
-
-#ifdef DEBUG
- re_token_type_t type = dfa->nodes[prev_node].type;
- assert (!IS_EPSILON_NODE (type));
-#endif
-#ifdef RE_ENABLE_I18N
- /* If the node may accept "multi byte". */
- if (dfa->nodes[prev_node].accept_mb)
- naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
- str_idx, sctx->last_str_idx);
-#endif /* RE_ENABLE_I18N */
-
- /* We don't check backreferences here.
- See update_cur_sifted_state(). */
- if (!naccepted
- && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
- && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
- dfa->nexts[prev_node]))
- naccepted = 1;
-
- if (naccepted == 0)
- continue;
-
- if (sctx->limits.nelem)
- {
- Idx to_idx = str_idx + naccepted;
- if (check_dst_limits (mctx, &sctx->limits,
- dfa->nexts[prev_node], to_idx,
- prev_node, str_idx))
- continue;
- }
- ok = re_node_set_insert (cur_dest, prev_node);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
-
- return REG_NOERROR;
-}
-
-/* Helper functions. */
-
-static reg_errcode_t
-internal_function
-clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx)
-{
- Idx top = mctx->state_log_top;
-
- if ((next_state_log_idx >= mctx->input.bufs_len
- && mctx->input.bufs_len < mctx->input.len)
- || (next_state_log_idx >= mctx->input.valid_len
- && mctx->input.valid_len < mctx->input.len))
- {
- reg_errcode_t err;
- err = extend_buffers (mctx, next_state_log_idx + 1);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
-
- if (top < next_state_log_idx)
- {
- memset (mctx->state_log + top + 1, '\0',
- sizeof (re_dfastate_t *) * (next_state_log_idx - top));
- mctx->state_log_top = next_state_log_idx;
- }
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function
-merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
- re_dfastate_t **src, Idx num)
-{
- Idx st_idx;
- reg_errcode_t err;
- for (st_idx = 0; st_idx < num; ++st_idx)
- {
- if (dst[st_idx] == NULL)
- dst[st_idx] = src[st_idx];
- else if (src[st_idx] != NULL)
- {
- re_node_set merged_set;
- err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
- &src[st_idx]->nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
- dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
- re_node_set_free (&merged_set);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- }
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function
-update_cur_sifted_state (const re_match_context_t *mctx,
- re_sift_context_t *sctx, Idx str_idx,
- re_node_set *dest_nodes)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err = REG_NOERROR;
- const re_node_set *candidates;
- candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
- : &mctx->state_log[str_idx]->nodes);
-
- if (dest_nodes->nelem == 0)
- sctx->sifted_states[str_idx] = NULL;
- else
- {
- if (candidates)
- {
- /* At first, add the nodes which can epsilon transit to a node in
- DEST_NODE. */
- err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- /* Then, check the limitations in the current sift_context. */
- if (sctx->limits.nelem)
- {
- err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
- mctx->bkref_ents, str_idx);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- }
-
- sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
-
- if (candidates && mctx->state_log[str_idx]->has_backref)
- {
- err = sift_states_bkref (mctx, sctx, str_idx, candidates);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
- const re_node_set *candidates)
-{
- reg_errcode_t err = REG_NOERROR;
- Idx i;
-
- re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- if (!state->inveclosure.alloc)
- {
- err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
- if (BE (err != REG_NOERROR, 0))
- return REG_ESPACE;
- for (i = 0; i < dest_nodes->nelem; i++)
- {
- err = re_node_set_merge (&state->inveclosure,
- dfa->inveclosures + dest_nodes->elems[i]);
- if (BE (err != REG_NOERROR, 0))
- return REG_ESPACE;
- }
- }
- return re_node_set_add_intersect (dest_nodes, candidates,
- &state->inveclosure);
-}
-
-static reg_errcode_t
-internal_function
-sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes,
- const re_node_set *candidates)
-{
- Idx ecl_idx;
- reg_errcode_t err;
- re_node_set *inv_eclosure = dfa->inveclosures + node;
- re_node_set except_nodes;
- re_node_set_init_empty (&except_nodes);
- for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
- {
- Idx cur_node = inv_eclosure->elems[ecl_idx];
- if (cur_node == node)
- continue;
- if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
- {
- Idx edst1 = dfa->edests[cur_node].elems[0];
- Idx edst2 = ((dfa->edests[cur_node].nelem > 1)
- ? dfa->edests[cur_node].elems[1] : REG_MISSING);
- if ((!re_node_set_contains (inv_eclosure, edst1)
- && re_node_set_contains (dest_nodes, edst1))
- || (REG_VALID_NONZERO_INDEX (edst2)
- && !re_node_set_contains (inv_eclosure, edst2)
- && re_node_set_contains (dest_nodes, edst2)))
- {
- err = re_node_set_add_intersect (&except_nodes, candidates,
- dfa->inveclosures + cur_node);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&except_nodes);
- return err;
- }
- }
- }
- }
- for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
- {
- Idx cur_node = inv_eclosure->elems[ecl_idx];
- if (!re_node_set_contains (&except_nodes, cur_node))
- {
- Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1;
- re_node_set_remove_at (dest_nodes, idx);
- }
- }
- re_node_set_free (&except_nodes);
- return REG_NOERROR;
-}
-
-static bool
-internal_function
-check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits,
- Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx lim_idx, src_pos, dst_pos;
-
- Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
- Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
- for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
- {
- Idx subexp_idx;
- struct re_backref_cache_entry *ent;
- ent = mctx->bkref_ents + limits->elems[lim_idx];
- subexp_idx = dfa->nodes[ent->node].opr.idx;
-
- dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
- subexp_idx, dst_node, dst_idx,
- dst_bkref_idx);
- src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
- subexp_idx, src_node, src_idx,
- src_bkref_idx);
-
- /* In case of:
- <src> <dst> ( <subexp> )
- ( <subexp> ) <src> <dst>
- ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
- if (src_pos == dst_pos)
- continue; /* This is unrelated limitation. */
- else
- return true;
- }
- return false;
-}
-
-static int
-internal_function
-check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
- Idx subexp_idx, Idx from_node, Idx bkref_idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- const re_node_set *eclosures = dfa->eclosures + from_node;
- Idx node_idx;
-
- /* Else, we are on the boundary: examine the nodes on the epsilon
- closure. */
- for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
- {
- Idx node = eclosures->elems[node_idx];
- switch (dfa->nodes[node].type)
- {
- case OP_BACK_REF:
- if (bkref_idx != REG_MISSING)
- {
- struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
- do
- {
- Idx dst;
- int cpos;
-
- if (ent->node != node)
- continue;
-
- if (subexp_idx < BITSET_WORD_BITS
- && !(ent->eps_reachable_subexps_map
- & ((bitset_word_t) 1 << subexp_idx)))
- continue;
-
- /* Recurse trying to reach the OP_OPEN_SUBEXP and
- OP_CLOSE_SUBEXP cases below. But, if the
- destination node is the same node as the source
- node, don't recurse because it would cause an
- infinite loop: a regex that exhibits this behavior
- is ()\1*\1* */
- dst = dfa->edests[node].elems[0];
- if (dst == from_node)
- {
- if (boundaries & 1)
- return -1;
- else /* if (boundaries & 2) */
- return 0;
- }
-
- cpos =
- check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
- dst, bkref_idx);
- if (cpos == -1 /* && (boundaries & 1) */)
- return -1;
- if (cpos == 0 && (boundaries & 2))
- return 0;
-
- if (subexp_idx < BITSET_WORD_BITS)
- ent->eps_reachable_subexps_map
- &= ~((bitset_word_t) 1 << subexp_idx);
- }
- while (ent++->more);
- }
- break;
-
- case OP_OPEN_SUBEXP:
- if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
- return -1;
- break;
-
- case OP_CLOSE_SUBEXP:
- if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
- return 0;
- break;
-
- default:
- break;
- }
- }
-
- return (boundaries & 2) ? 1 : 0;
-}
-
-static int
-internal_function
-check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit,
- Idx subexp_idx, Idx from_node, Idx str_idx,
- Idx bkref_idx)
-{
- struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
- int boundaries;
-
- /* If we are outside the range of the subexpression, return -1 or 1. */
- if (str_idx < lim->subexp_from)
- return -1;
-
- if (lim->subexp_to < str_idx)
- return 1;
-
- /* If we are within the subexpression, return 0. */
- boundaries = (str_idx == lim->subexp_from);
- boundaries |= (str_idx == lim->subexp_to) << 1;
- if (boundaries == 0)
- return 0;
-
- /* Else, examine epsilon closure. */
- return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
- from_node, bkref_idx);
-}
-
-/* Check the limitations of sub expressions LIMITS, and remove the nodes
- which are against limitations from DEST_NODES. */
-
-static reg_errcode_t
-internal_function
-check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
- const re_node_set *candidates, re_node_set *limits,
- struct re_backref_cache_entry *bkref_ents, Idx str_idx)
-{
- reg_errcode_t err;
- Idx node_idx, lim_idx;
-
- for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
- {
- Idx subexp_idx;
- struct re_backref_cache_entry *ent;
- ent = bkref_ents + limits->elems[lim_idx];
-
- if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
- continue; /* This is unrelated limitation. */
-
- subexp_idx = dfa->nodes[ent->node].opr.idx;
- if (ent->subexp_to == str_idx)
- {
- Idx ops_node = REG_MISSING;
- Idx cls_node = REG_MISSING;
- for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
- {
- Idx node = dest_nodes->elems[node_idx];
- re_token_type_t type = dfa->nodes[node].type;
- if (type == OP_OPEN_SUBEXP
- && subexp_idx == dfa->nodes[node].opr.idx)
- ops_node = node;
- else if (type == OP_CLOSE_SUBEXP
- && subexp_idx == dfa->nodes[node].opr.idx)
- cls_node = node;
- }
-
- /* Check the limitation of the open subexpression. */
- /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
- if (REG_VALID_INDEX (ops_node))
- {
- err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
- candidates);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
-
- /* Check the limitation of the close subexpression. */
- if (REG_VALID_INDEX (cls_node))
- for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
- {
- Idx node = dest_nodes->elems[node_idx];
- if (!re_node_set_contains (dfa->inveclosures + node,
- cls_node)
- && !re_node_set_contains (dfa->eclosures + node,
- cls_node))
- {
- /* It is against this limitation.
- Remove it form the current sifted state. */
- err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
- candidates);
- if (BE (err != REG_NOERROR, 0))
- return err;
- --node_idx;
- }
- }
- }
- else /* (ent->subexp_to != str_idx) */
- {
- for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
- {
- Idx node = dest_nodes->elems[node_idx];
- re_token_type_t type = dfa->nodes[node].type;
- if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
- {
- if (subexp_idx != dfa->nodes[node].opr.idx)
- continue;
- /* It is against this limitation.
- Remove it form the current sifted state. */
- err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
- candidates);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- }
- }
- }
- return REG_NOERROR;
-}
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
- Idx str_idx, const re_node_set *candidates)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err;
- Idx node_idx, node;
- re_sift_context_t local_sctx;
- Idx first_idx = search_cur_bkref_entry (mctx, str_idx);
-
- if (first_idx == REG_MISSING)
- return REG_NOERROR;
-
- local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
-
- for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
- {
- Idx enabled_idx;
- re_token_type_t type;
- struct re_backref_cache_entry *entry;
- node = candidates->elems[node_idx];
- type = dfa->nodes[node].type;
- /* Avoid infinite loop for the REs like "()\1+". */
- if (node == sctx->last_node && str_idx == sctx->last_str_idx)
- continue;
- if (type != OP_BACK_REF)
- continue;
-
- entry = mctx->bkref_ents + first_idx;
- enabled_idx = first_idx;
- do
- {
- Idx subexp_len;
- Idx to_idx;
- Idx dst_node;
- bool ok;
- re_dfastate_t *cur_state;
-
- if (entry->node != node)
- continue;
- subexp_len = entry->subexp_to - entry->subexp_from;
- to_idx = str_idx + subexp_len;
- dst_node = (subexp_len ? dfa->nexts[node]
- : dfa->edests[node].elems[0]);
-
- if (to_idx > sctx->last_str_idx
- || sctx->sifted_states[to_idx] == NULL
- || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
- || check_dst_limits (mctx, &sctx->limits, node,
- str_idx, dst_node, to_idx))
- continue;
-
- if (local_sctx.sifted_states == NULL)
- {
- local_sctx = *sctx;
- err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
- local_sctx.last_node = node;
- local_sctx.last_str_idx = str_idx;
- ok = re_node_set_insert (&local_sctx.limits, enabled_idx);
- if (BE (! ok, 0))
- {
- err = REG_ESPACE;
- goto free_return;
- }
- cur_state = local_sctx.sifted_states[str_idx];
- err = sift_states_backward (mctx, &local_sctx);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- if (sctx->limited_states != NULL)
- {
- err = merge_state_array (dfa, sctx->limited_states,
- local_sctx.sifted_states,
- str_idx + 1);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
- local_sctx.sifted_states[str_idx] = cur_state;
- re_node_set_remove (&local_sctx.limits, enabled_idx);
-
- /* mctx->bkref_ents may have changed, reload the pointer. */
- entry = mctx->bkref_ents + enabled_idx;
- }
- while (enabled_idx++, entry++->more);
- }
- err = REG_NOERROR;
- free_return:
- if (local_sctx.sifted_states != NULL)
- {
- re_node_set_free (&local_sctx.limits);
- }
-
- return err;
-}
-
-
-#ifdef RE_ENABLE_I18N
-static int
-internal_function
-sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
- Idx node_idx, Idx str_idx, Idx max_str_idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- int naccepted;
- /* Check the node can accept "multi byte". */
- naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
- if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
- !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
- dfa->nexts[node_idx]))
- /* The node can't accept the "multi byte", or the
- destination was already thrown away, then the node
- could't accept the current input "multi byte". */
- naccepted = 0;
- /* Otherwise, it is sure that the node could accept
- 'naccepted' bytes input. */
- return naccepted;
-}
-#endif /* RE_ENABLE_I18N */
-
-
-/* Functions for state transition. */
-
-/* Return the next state to which the current state STATE will transit by
- accepting the current input byte, and update STATE_LOG if necessary.
- If STATE can accept a multibyte char/collating element/back reference
- update the destination of STATE_LOG. */
-
-static re_dfastate_t *
-internal_function __attribute_warn_unused_result__
-transit_state (reg_errcode_t *err, re_match_context_t *mctx,
- re_dfastate_t *state)
-{
- re_dfastate_t **trtable;
- unsigned char ch;
-
-#ifdef RE_ENABLE_I18N
- /* If the current state can accept multibyte. */
- if (BE (state->accept_mb, 0))
- {
- *err = transit_state_mb (mctx, state);
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
- }
-#endif /* RE_ENABLE_I18N */
-
- /* Then decide the next state with the single byte. */
-#if 0
- if (0)
- /* don't use transition table */
- return transit_state_sb (err, mctx, state);
-#endif
-
- /* Use transition table */
- ch = re_string_fetch_byte (&mctx->input);
- for (;;)
- {
- trtable = state->trtable;
- if (BE (trtable != NULL, 1))
- return trtable[ch];
-
- trtable = state->word_trtable;
- if (BE (trtable != NULL, 1))
- {
- unsigned int context;
- context
- = re_string_context_at (&mctx->input,
- re_string_cur_idx (&mctx->input) - 1,
- mctx->eflags);
- if (IS_WORD_CONTEXT (context))
- return trtable[ch + SBC_MAX];
- else
- return trtable[ch];
- }
-
- if (!build_trtable (mctx->dfa, state))
- {
- *err = REG_ESPACE;
- return NULL;
- }
-
- /* Retry, we now have a transition table. */
- }
-}
-
-/* Update the state_log if we need */
-static re_dfastate_t *
-internal_function
-merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
- re_dfastate_t *next_state)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx cur_idx = re_string_cur_idx (&mctx->input);
-
- if (cur_idx > mctx->state_log_top)
- {
- mctx->state_log[cur_idx] = next_state;
- mctx->state_log_top = cur_idx;
- }
- else if (mctx->state_log[cur_idx] == 0)
- {
- mctx->state_log[cur_idx] = next_state;
- }
- else
- {
- re_dfastate_t *pstate;
- unsigned int context;
- re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
- /* If (state_log[cur_idx] != 0), it implies that cur_idx is
- the destination of a multibyte char/collating element/
- back reference. Then the next state is the union set of
- these destinations and the results of the transition table. */
- pstate = mctx->state_log[cur_idx];
- log_nodes = pstate->entrance_nodes;
- if (next_state != NULL)
- {
- table_nodes = next_state->entrance_nodes;
- *err = re_node_set_init_union (&next_nodes, table_nodes,
- log_nodes);
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
- }
- else
- next_nodes = *log_nodes;
- /* Note: We already add the nodes of the initial state,
- then we don't need to add them here. */
-
- context = re_string_context_at (&mctx->input,
- re_string_cur_idx (&mctx->input) - 1,
- mctx->eflags);
- next_state = mctx->state_log[cur_idx]
- = re_acquire_state_context (err, dfa, &next_nodes, context);
- /* We don't need to check errors here, since the return value of
- this function is next_state and ERR is already set. */
-
- if (table_nodes != NULL)
- re_node_set_free (&next_nodes);
- }
-
- if (BE (dfa->nbackref, 0) && next_state != NULL)
- {
- /* Check OP_OPEN_SUBEXP in the current state in case that we use them
- later. We must check them here, since the back references in the
- next state might use them. */
- *err = check_subexp_matching_top (mctx, &next_state->nodes,
- cur_idx);
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
-
- /* If the next state has back references. */
- if (next_state->has_backref)
- {
- *err = transit_state_bkref (mctx, &next_state->nodes);
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
- next_state = mctx->state_log[cur_idx];
- }
- }
-
- return next_state;
-}
-
-/* Skip bytes in the input that correspond to part of a
- multi-byte match, then look in the log for a state
- from which to restart matching. */
-static re_dfastate_t *
-internal_function
-find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
-{
- re_dfastate_t *cur_state;
- do
- {
- Idx max = mctx->state_log_top;
- Idx cur_str_idx = re_string_cur_idx (&mctx->input);
-
- do
- {
- if (++cur_str_idx > max)
- return NULL;
- re_string_skip_bytes (&mctx->input, 1);
- }
- while (mctx->state_log[cur_str_idx] == NULL);
-
- cur_state = merge_state_with_log (err, mctx, NULL);
- }
- while (*err == REG_NOERROR && cur_state == NULL);
- return cur_state;
-}
-
-/* Helper functions for transit_state. */
-
-/* From the node set CUR_NODES, pick up the nodes whose types are
- OP_OPEN_SUBEXP and which have corresponding back references in the regular
- expression. And register them to use them later for evaluating the
- corresponding back references. */
-
-static reg_errcode_t
-internal_function
-check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
- Idx str_idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx node_idx;
- reg_errcode_t err;
-
- /* TODO: This isn't efficient.
- Because there might be more than one nodes whose types are
- OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
- nodes.
- E.g. RE: (a){2} */
- for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
- {
- Idx node = cur_nodes->elems[node_idx];
- if (dfa->nodes[node].type == OP_OPEN_SUBEXP
- && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
- && (dfa->used_bkref_map
- & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
- {
- err = match_ctx_add_subtop (mctx, node, str_idx);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- }
- return REG_NOERROR;
-}
-
-#if 0
-/* Return the next state to which the current state STATE will transit by
- accepting the current input byte. */
-
-static re_dfastate_t *
-transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
- re_dfastate_t *state)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- re_node_set next_nodes;
- re_dfastate_t *next_state;
- Idx node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
- unsigned int context;
-
- *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
- if (BE (*err != REG_NOERROR, 0))
- return NULL;
- for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
- {
- Idx cur_node = state->nodes.elems[node_cnt];
- if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
- {
- *err = re_node_set_merge (&next_nodes,
- dfa->eclosures + dfa->nexts[cur_node]);
- if (BE (*err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return NULL;
- }
- }
- }
- context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
- next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
- /* We don't need to check errors here, since the return value of
- this function is next_state and ERR is already set. */
-
- re_node_set_free (&next_nodes);
- re_string_skip_bytes (&mctx->input, 1);
- return next_state;
-}
-#endif
-
-#ifdef RE_ENABLE_I18N
-static reg_errcode_t
-internal_function
-transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err;
- Idx i;
-
- for (i = 0; i < pstate->nodes.nelem; ++i)
- {
- re_node_set dest_nodes, *new_nodes;
- Idx cur_node_idx = pstate->nodes.elems[i];
- int naccepted;
- Idx dest_idx;
- unsigned int context;
- re_dfastate_t *dest_state;
-
- if (!dfa->nodes[cur_node_idx].accept_mb)
- continue;
-
- if (dfa->nodes[cur_node_idx].constraint)
- {
- context = re_string_context_at (&mctx->input,
- re_string_cur_idx (&mctx->input),
- mctx->eflags);
- if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
- context))
- continue;
- }
-
- /* How many bytes the node can accept? */
- naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
- re_string_cur_idx (&mctx->input));
- if (naccepted == 0)
- continue;
-
- /* The node can accepts 'naccepted' bytes. */
- dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
- mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
- : mctx->max_mb_elem_len);
- err = clean_state_log_if_needed (mctx, dest_idx);
- if (BE (err != REG_NOERROR, 0))
- return err;
-#ifdef DEBUG
- assert (dfa->nexts[cur_node_idx] != REG_MISSING);
-#endif
- new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
-
- dest_state = mctx->state_log[dest_idx];
- if (dest_state == NULL)
- dest_nodes = *new_nodes;
- else
- {
- err = re_node_set_init_union (&dest_nodes,
- dest_state->entrance_nodes, new_nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- context = re_string_context_at (&mctx->input, dest_idx - 1,
- mctx->eflags);
- mctx->state_log[dest_idx]
- = re_acquire_state_context (&err, dfa, &dest_nodes, context);
- if (dest_state != NULL)
- re_node_set_free (&dest_nodes);
- if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
- return err;
- }
- return REG_NOERROR;
-}
-#endif /* RE_ENABLE_I18N */
-
-static reg_errcode_t
-internal_function
-transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err;
- Idx i;
- Idx cur_str_idx = re_string_cur_idx (&mctx->input);
-
- for (i = 0; i < nodes->nelem; ++i)
- {
- Idx dest_str_idx, prev_nelem, bkc_idx;
- Idx node_idx = nodes->elems[i];
- unsigned int context;
- const re_token_t *node = dfa->nodes + node_idx;
- re_node_set *new_dest_nodes;
-
- /* Check whether 'node' is a backreference or not. */
- if (node->type != OP_BACK_REF)
- continue;
-
- if (node->constraint)
- {
- context = re_string_context_at (&mctx->input, cur_str_idx,
- mctx->eflags);
- if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
- continue;
- }
-
- /* 'node' is a backreference.
- Check the substring which the substring matched. */
- bkc_idx = mctx->nbkref_ents;
- err = get_subexp (mctx, node_idx, cur_str_idx);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
-
- /* And add the epsilon closures (which is 'new_dest_nodes') of
- the backreference to appropriate state_log. */
-#ifdef DEBUG
- assert (dfa->nexts[node_idx] != REG_MISSING);
-#endif
- for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
- {
- Idx subexp_len;
- re_dfastate_t *dest_state;
- struct re_backref_cache_entry *bkref_ent;
- bkref_ent = mctx->bkref_ents + bkc_idx;
- if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
- continue;
- subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
- new_dest_nodes = (subexp_len == 0
- ? dfa->eclosures + dfa->edests[node_idx].elems[0]
- : dfa->eclosures + dfa->nexts[node_idx]);
- dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
- - bkref_ent->subexp_from);
- context = re_string_context_at (&mctx->input, dest_str_idx - 1,
- mctx->eflags);
- dest_state = mctx->state_log[dest_str_idx];
- prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
- : mctx->state_log[cur_str_idx]->nodes.nelem);
- /* Add 'new_dest_node' to state_log. */
- if (dest_state == NULL)
- {
- mctx->state_log[dest_str_idx]
- = re_acquire_state_context (&err, dfa, new_dest_nodes,
- context);
- if (BE (mctx->state_log[dest_str_idx] == NULL
- && err != REG_NOERROR, 0))
- goto free_return;
- }
- else
- {
- re_node_set dest_nodes;
- err = re_node_set_init_union (&dest_nodes,
- dest_state->entrance_nodes,
- new_dest_nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&dest_nodes);
- goto free_return;
- }
- mctx->state_log[dest_str_idx]
- = re_acquire_state_context (&err, dfa, &dest_nodes, context);
- re_node_set_free (&dest_nodes);
- if (BE (mctx->state_log[dest_str_idx] == NULL
- && err != REG_NOERROR, 0))
- goto free_return;
- }
- /* We need to check recursively if the backreference can epsilon
- transit. */
- if (subexp_len == 0
- && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
- {
- err = check_subexp_matching_top (mctx, new_dest_nodes,
- cur_str_idx);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- err = transit_state_bkref (mctx, new_dest_nodes);
- if (BE (err != REG_NOERROR, 0))
- goto free_return;
- }
- }
- }
- err = REG_NOERROR;
- free_return:
- return err;
-}
-
-/* Enumerate all the candidates which the backreference BKREF_NODE can match
- at BKREF_STR_IDX, and register them by match_ctx_add_entry().
- Note that we might collect inappropriate candidates here.
- However, the cost of checking them strictly here is too high, then we
- delay these checking for prune_impossible_nodes(). */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- Idx subexp_num, sub_top_idx;
- const char *buf = (const char *) re_string_get_buffer (&mctx->input);
- /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
- Idx cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
- if (cache_idx != REG_MISSING)
- {
- const struct re_backref_cache_entry *entry
- = mctx->bkref_ents + cache_idx;
- do
- if (entry->node == bkref_node)
- return REG_NOERROR; /* We already checked it. */
- while (entry++->more);
- }
-
- subexp_num = dfa->nodes[bkref_node].opr.idx;
-
- /* For each sub expression */
- for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
- {
- reg_errcode_t err;
- re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
- re_sub_match_last_t *sub_last;
- Idx sub_last_idx, sl_str, bkref_str_off;
-
- if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
- continue; /* It isn't related. */
-
- sl_str = sub_top->str_idx;
- bkref_str_off = bkref_str_idx;
- /* At first, check the last node of sub expressions we already
- evaluated. */
- for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
- {
- regoff_t sl_str_diff;
- sub_last = sub_top->lasts[sub_last_idx];
- sl_str_diff = sub_last->str_idx - sl_str;
- /* The matched string by the sub expression match with the substring
- at the back reference? */
- if (sl_str_diff > 0)
- {
- if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
- {
- /* Not enough chars for a successful match. */
- if (bkref_str_off + sl_str_diff > mctx->input.len)
- break;
-
- err = clean_state_log_if_needed (mctx,
- bkref_str_off
- + sl_str_diff);
- if (BE (err != REG_NOERROR, 0))
- return err;
- buf = (const char *) re_string_get_buffer (&mctx->input);
- }
- if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
- /* We don't need to search this sub expression any more. */
- break;
- }
- bkref_str_off += sl_str_diff;
- sl_str += sl_str_diff;
- err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
- bkref_str_idx);
-
- /* Reload buf, since the preceding call might have reallocated
- the buffer. */
- buf = (const char *) re_string_get_buffer (&mctx->input);
-
- if (err == REG_NOMATCH)
- continue;
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
-
- if (sub_last_idx < sub_top->nlasts)
- continue;
- if (sub_last_idx > 0)
- ++sl_str;
- /* Then, search for the other last nodes of the sub expression. */
- for (; sl_str <= bkref_str_idx; ++sl_str)
- {
- Idx cls_node;
- regoff_t sl_str_off;
- const re_node_set *nodes;
- sl_str_off = sl_str - sub_top->str_idx;
- /* The matched string by the sub expression match with the substring
- at the back reference? */
- if (sl_str_off > 0)
- {
- if (BE (bkref_str_off >= mctx->input.valid_len, 0))
- {
- /* If we are at the end of the input, we cannot match. */
- if (bkref_str_off >= mctx->input.len)
- break;
-
- err = extend_buffers (mctx, bkref_str_off + 1);
- if (BE (err != REG_NOERROR, 0))
- return err;
-
- buf = (const char *) re_string_get_buffer (&mctx->input);
- }
- if (buf [bkref_str_off++] != buf[sl_str - 1])
- break; /* We don't need to search this sub expression
- any more. */
- }
- if (mctx->state_log[sl_str] == NULL)
- continue;
- /* Does this state have a ')' of the sub expression? */
- nodes = &mctx->state_log[sl_str]->nodes;
- cls_node = find_subexp_node (dfa, nodes, subexp_num,
- OP_CLOSE_SUBEXP);
- if (cls_node == REG_MISSING)
- continue; /* No. */
- if (sub_top->path == NULL)
- {
- sub_top->path = calloc (sizeof (state_array_t),
- sl_str - sub_top->str_idx + 1);
- if (sub_top->path == NULL)
- return REG_ESPACE;
- }
- /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
- in the current context? */
- err = check_arrival (mctx, sub_top->path, sub_top->node,
- sub_top->str_idx, cls_node, sl_str,
- OP_CLOSE_SUBEXP);
- if (err == REG_NOMATCH)
- continue;
- if (BE (err != REG_NOERROR, 0))
- return err;
- sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
- if (BE (sub_last == NULL, 0))
- return REG_ESPACE;
- err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
- bkref_str_idx);
- if (err == REG_NOMATCH)
- continue;
- }
- }
- return REG_NOERROR;
-}
-
-/* Helper functions for get_subexp(). */
-
-/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
- If it can arrive, register the sub expression expressed with SUB_TOP
- and SUB_LAST. */
-
-static reg_errcode_t
-internal_function
-get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
- re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str)
-{
- reg_errcode_t err;
- Idx to_idx;
- /* Can the subexpression arrive the back reference? */
- err = check_arrival (mctx, &sub_last->path, sub_last->node,
- sub_last->str_idx, bkref_node, bkref_str,
- OP_OPEN_SUBEXP);
- if (err != REG_NOERROR)
- return err;
- err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
- sub_last->str_idx);
- if (BE (err != REG_NOERROR, 0))
- return err;
- to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
- return clean_state_log_if_needed (mctx, to_idx);
-}
-
-/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
- Search '(' if FL_OPEN, or search ')' otherwise.
- TODO: This function isn't efficient...
- Because there might be more than one nodes whose types are
- OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
- nodes.
- E.g. RE: (a){2} */
-
-static Idx
-internal_function
-find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
- Idx subexp_idx, int type)
-{
- Idx cls_idx;
- for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
- {
- Idx cls_node = nodes->elems[cls_idx];
- const re_token_t *node = dfa->nodes + cls_node;
- if (node->type == type
- && node->opr.idx == subexp_idx)
- return cls_node;
- }
- return REG_MISSING;
-}
-
-/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
- LAST_NODE at LAST_STR. We record the path onto PATH since it will be
- heavily reused.
- Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_node,
- Idx top_str, Idx last_node, Idx last_str, int type)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err = REG_NOERROR;
- Idx subexp_num, backup_cur_idx, str_idx, null_cnt;
- re_dfastate_t *cur_state = NULL;
- re_node_set *cur_nodes, next_nodes;
- re_dfastate_t **backup_state_log;
- unsigned int context;
-
- subexp_num = dfa->nodes[top_node].opr.idx;
- /* Extend the buffer if we need. */
- if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
- {
- re_dfastate_t **new_array;
- Idx old_alloc = path->alloc;
- Idx incr_alloc = last_str + mctx->max_mb_elem_len + 1;
- Idx new_alloc;
- if (BE (IDX_MAX - old_alloc < incr_alloc, 0))
- return REG_ESPACE;
- new_alloc = old_alloc + incr_alloc;
- if (BE (SIZE_MAX / sizeof (re_dfastate_t *) < new_alloc, 0))
- return REG_ESPACE;
- new_array = re_realloc (path->array, re_dfastate_t *, new_alloc);
- if (BE (new_array == NULL, 0))
- return REG_ESPACE;
- path->array = new_array;
- path->alloc = new_alloc;
- memset (new_array + old_alloc, '\0',
- sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
- }
-
- str_idx = path->next_idx ? path->next_idx : top_str;
-
- /* Temporary modify MCTX. */
- backup_state_log = mctx->state_log;
- backup_cur_idx = mctx->input.cur_idx;
- mctx->state_log = path->array;
- mctx->input.cur_idx = str_idx;
-
- /* Setup initial node set. */
- context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
- if (str_idx == top_str)
- {
- err = re_node_set_init_1 (&next_nodes, top_node);
- if (BE (err != REG_NOERROR, 0))
- return err;
- err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- }
- else
- {
- cur_state = mctx->state_log[str_idx];
- if (cur_state && cur_state->has_backref)
- {
- err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- else
- re_node_set_init_empty (&next_nodes);
- }
- if (str_idx == top_str || (cur_state && cur_state->has_backref))
- {
- if (next_nodes.nelem)
- {
- err = expand_bkref_cache (mctx, &next_nodes, str_idx,
- subexp_num, type);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- }
- cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
- if (BE (cur_state == NULL && err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- mctx->state_log[str_idx] = cur_state;
- }
-
- for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
- {
- re_node_set_empty (&next_nodes);
- if (mctx->state_log[str_idx + 1])
- {
- err = re_node_set_merge (&next_nodes,
- &mctx->state_log[str_idx + 1]->nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- }
- if (cur_state)
- {
- err = check_arrival_add_next_nodes (mctx, str_idx,
- &cur_state->non_eps_nodes,
- &next_nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- }
- ++str_idx;
- if (next_nodes.nelem)
- {
- err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- err = expand_bkref_cache (mctx, &next_nodes, str_idx,
- subexp_num, type);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- }
- context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
- cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
- if (BE (cur_state == NULL && err != REG_NOERROR, 0))
- {
- re_node_set_free (&next_nodes);
- return err;
- }
- mctx->state_log[str_idx] = cur_state;
- null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
- }
- re_node_set_free (&next_nodes);
- cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
- : &mctx->state_log[last_str]->nodes);
- path->next_idx = str_idx;
-
- /* Fix MCTX. */
- mctx->state_log = backup_state_log;
- mctx->input.cur_idx = backup_cur_idx;
-
- /* Then check the current node set has the node LAST_NODE. */
- if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
- return REG_NOERROR;
-
- return REG_NOMATCH;
-}
-
-/* Helper functions for check_arrival. */
-
-/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
- to NEXT_NODES.
- TODO: This function is similar to the functions transit_state*(),
- however this function has many additional works.
- Can't we unify them? */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-check_arrival_add_next_nodes (re_match_context_t *mctx, Idx str_idx,
- re_node_set *cur_nodes, re_node_set *next_nodes)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- bool ok;
- Idx cur_idx;
-#ifdef RE_ENABLE_I18N
- reg_errcode_t err = REG_NOERROR;
-#endif
- re_node_set union_set;
- re_node_set_init_empty (&union_set);
- for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
- {
- int naccepted = 0;
- Idx cur_node = cur_nodes->elems[cur_idx];
-#ifdef DEBUG
- re_token_type_t type = dfa->nodes[cur_node].type;
- assert (!IS_EPSILON_NODE (type));
-#endif
-#ifdef RE_ENABLE_I18N
- /* If the node may accept "multi byte". */
- if (dfa->nodes[cur_node].accept_mb)
- {
- naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
- str_idx);
- if (naccepted > 1)
- {
- re_dfastate_t *dest_state;
- Idx next_node = dfa->nexts[cur_node];
- Idx next_idx = str_idx + naccepted;
- dest_state = mctx->state_log[next_idx];
- re_node_set_empty (&union_set);
- if (dest_state)
- {
- err = re_node_set_merge (&union_set, &dest_state->nodes);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&union_set);
- return err;
- }
- }
- ok = re_node_set_insert (&union_set, next_node);
- if (BE (! ok, 0))
- {
- re_node_set_free (&union_set);
- return REG_ESPACE;
- }
- mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
- &union_set);
- if (BE (mctx->state_log[next_idx] == NULL
- && err != REG_NOERROR, 0))
- {
- re_node_set_free (&union_set);
- return err;
- }
- }
- }
-#endif /* RE_ENABLE_I18N */
- if (naccepted
- || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
- {
- ok = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
- if (BE (! ok, 0))
- {
- re_node_set_free (&union_set);
- return REG_ESPACE;
- }
- }
- }
- re_node_set_free (&union_set);
- return REG_NOERROR;
-}
-
-/* For all the nodes in CUR_NODES, add the epsilon closures of them to
- CUR_NODES, however exclude the nodes which are:
- - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
- - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
-*/
-
-static reg_errcode_t
-internal_function
-check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
- Idx ex_subexp, int type)
-{
- reg_errcode_t err;
- Idx idx, outside_node;
- re_node_set new_nodes;
-#ifdef DEBUG
- assert (cur_nodes->nelem);
-#endif
- err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
- if (BE (err != REG_NOERROR, 0))
- return err;
- /* Create a new node set NEW_NODES with the nodes which are epsilon
- closures of the node in CUR_NODES. */
-
- for (idx = 0; idx < cur_nodes->nelem; ++idx)
- {
- Idx cur_node = cur_nodes->elems[idx];
- const re_node_set *eclosure = dfa->eclosures + cur_node;
- outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
- if (outside_node == REG_MISSING)
- {
- /* There are no problematic nodes, just merge them. */
- err = re_node_set_merge (&new_nodes, eclosure);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&new_nodes);
- return err;
- }
- }
- else
- {
- /* There are problematic nodes, re-calculate incrementally. */
- err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
- ex_subexp, type);
- if (BE (err != REG_NOERROR, 0))
- {
- re_node_set_free (&new_nodes);
- return err;
- }
- }
- }
- re_node_set_free (cur_nodes);
- *cur_nodes = new_nodes;
- return REG_NOERROR;
-}
-
-/* Helper function for check_arrival_expand_ecl.
- Check incrementally the epsilon closure of TARGET, and if it isn't
- problematic append it to DST_NODES. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
- Idx target, Idx ex_subexp, int type)
-{
- Idx cur_node;
- for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
- {
- bool ok;
-
- if (dfa->nodes[cur_node].type == type
- && dfa->nodes[cur_node].opr.idx == ex_subexp)
- {
- if (type == OP_CLOSE_SUBEXP)
- {
- ok = re_node_set_insert (dst_nodes, cur_node);
- if (BE (! ok, 0))
- return REG_ESPACE;
- }
- break;
- }
- ok = re_node_set_insert (dst_nodes, cur_node);
- if (BE (! ok, 0))
- return REG_ESPACE;
- if (dfa->edests[cur_node].nelem == 0)
- break;
- if (dfa->edests[cur_node].nelem == 2)
- {
- reg_errcode_t err;
- err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
- dfa->edests[cur_node].elems[1],
- ex_subexp, type);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- cur_node = dfa->edests[cur_node].elems[0];
- }
- return REG_NOERROR;
-}
-
-
-/* For all the back references in the current state, calculate the
- destination of the back references by the appropriate entry
- in MCTX->BKREF_ENTS. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
- Idx cur_str, Idx subexp_num, int type)
-{
- const re_dfa_t *const dfa = mctx->dfa;
- reg_errcode_t err;
- Idx cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
- struct re_backref_cache_entry *ent;
-
- if (cache_idx_start == REG_MISSING)
- return REG_NOERROR;
-
- restart:
- ent = mctx->bkref_ents + cache_idx_start;
- do
- {
- Idx to_idx, next_node;
-
- /* Is this entry ENT is appropriate? */
- if (!re_node_set_contains (cur_nodes, ent->node))
- continue; /* No. */
-
- to_idx = cur_str + ent->subexp_to - ent->subexp_from;
- /* Calculate the destination of the back reference, and append it
- to MCTX->STATE_LOG. */
- if (to_idx == cur_str)
- {
- /* The backreference did epsilon transit, we must re-check all the
- node in the current state. */
- re_node_set new_dests;
- reg_errcode_t err2, err3;
- next_node = dfa->edests[ent->node].elems[0];
- if (re_node_set_contains (cur_nodes, next_node))
- continue;
- err = re_node_set_init_1 (&new_dests, next_node);
- err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
- err3 = re_node_set_merge (cur_nodes, &new_dests);
- re_node_set_free (&new_dests);
- if (BE (err != REG_NOERROR || err2 != REG_NOERROR
- || err3 != REG_NOERROR, 0))
- {
- err = (err != REG_NOERROR ? err
- : (err2 != REG_NOERROR ? err2 : err3));
- return err;
- }
- /* TODO: It is still inefficient... */
- goto restart;
- }
- else
- {
- re_node_set union_set;
- next_node = dfa->nexts[ent->node];
- if (mctx->state_log[to_idx])
- {
- bool ok;
- if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
- next_node))
- continue;
- err = re_node_set_init_copy (&union_set,
- &mctx->state_log[to_idx]->nodes);
- ok = re_node_set_insert (&union_set, next_node);
- if (BE (err != REG_NOERROR || ! ok, 0))
- {
- re_node_set_free (&union_set);
- err = err != REG_NOERROR ? err : REG_ESPACE;
- return err;
- }
- }
- else
- {
- err = re_node_set_init_1 (&union_set, next_node);
- if (BE (err != REG_NOERROR, 0))
- return err;
- }
- mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
- re_node_set_free (&union_set);
- if (BE (mctx->state_log[to_idx] == NULL
- && err != REG_NOERROR, 0))
- return err;
- }
- }
- while (ent++->more);
- return REG_NOERROR;
-}
-
-/* Build transition table for the state.
- Return true if successful. */
-
-static bool
-internal_function
-build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
-{
- reg_errcode_t err;
- Idx i, j;
- int ch;
- bool need_word_trtable = false;
- bitset_word_t elem, mask;
- bool dests_node_malloced = false;
- bool dest_states_malloced = false;
- Idx ndests; /* Number of the destination states from 'state'. */
- re_dfastate_t **trtable;
- re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
- re_node_set follows, *dests_node;
- bitset_t *dests_ch;
- bitset_t acceptable;
-
- struct dests_alloc
- {
- re_node_set dests_node[SBC_MAX];
- bitset_t dests_ch[SBC_MAX];
- } *dests_alloc;
-
- /* We build DFA states which corresponds to the destination nodes
- from 'state'. 'dests_node[i]' represents the nodes which i-th
- destination state contains, and 'dests_ch[i]' represents the
- characters which i-th destination state accepts. */
- if (__libc_use_alloca (sizeof (struct dests_alloc)))
- dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
- else
- {
- dests_alloc = re_malloc (struct dests_alloc, 1);
- if (BE (dests_alloc == NULL, 0))
- return false;
- dests_node_malloced = true;
- }
- dests_node = dests_alloc->dests_node;
- dests_ch = dests_alloc->dests_ch;
-
- /* Initialize transition table. */
- state->word_trtable = state->trtable = NULL;
-
- /* At first, group all nodes belonging to 'state' into several
- destinations. */
- ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
- if (BE (! REG_VALID_NONZERO_INDEX (ndests), 0))
- {
- if (dests_node_malloced)
- free (dests_alloc);
- /* Return false in case of an error, true otherwise. */
- if (ndests == 0)
- {
- state->trtable = (re_dfastate_t **)
- calloc (sizeof (re_dfastate_t *), SBC_MAX);
- if (BE (state->trtable == NULL, 0))
- return false;
- return true;
- }
- return false;
- }
-
- err = re_node_set_alloc (&follows, ndests + 1);
- if (BE (err != REG_NOERROR, 0))
- goto out_free;
-
- /* Avoid arithmetic overflow in size calculation. */
- if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX)
- / (3 * sizeof (re_dfastate_t *)))
- < ndests),
- 0))
- goto out_free;
-
- if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
- + ndests * 3 * sizeof (re_dfastate_t *)))
- dest_states = (re_dfastate_t **)
- alloca (ndests * 3 * sizeof (re_dfastate_t *));
- else
- {
- dest_states = (re_dfastate_t **)
- malloc (ndests * 3 * sizeof (re_dfastate_t *));
- if (BE (dest_states == NULL, 0))
- {
-out_free:
- if (dest_states_malloced)
- free (dest_states);
- re_node_set_free (&follows);
- for (i = 0; i < ndests; ++i)
- re_node_set_free (dests_node + i);
- if (dests_node_malloced)
- free (dests_alloc);
- return false;
- }
- dest_states_malloced = true;
- }
- dest_states_word = dest_states + ndests;
- dest_states_nl = dest_states_word + ndests;
- bitset_empty (acceptable);
-
- /* Then build the states for all destinations. */
- for (i = 0; i < ndests; ++i)
- {
- Idx next_node;
- re_node_set_empty (&follows);
- /* Merge the follows of this destination states. */
- for (j = 0; j < dests_node[i].nelem; ++j)
- {
- next_node = dfa->nexts[dests_node[i].elems[j]];
- if (next_node != REG_MISSING)
- {
- err = re_node_set_merge (&follows, dfa->eclosures + next_node);
- if (BE (err != REG_NOERROR, 0))
- goto out_free;
- }
- }
- dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
- if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
- goto out_free;
- /* If the new state has context constraint,
- build appropriate states for these contexts. */
- if (dest_states[i]->has_constraint)
- {
- dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
- CONTEXT_WORD);
- if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
- goto out_free;
-
- if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
- need_word_trtable = true;
-
- dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
- CONTEXT_NEWLINE);
- if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
- goto out_free;
- }
- else
- {
- dest_states_word[i] = dest_states[i];
- dest_states_nl[i] = dest_states[i];
- }
- bitset_merge (acceptable, dests_ch[i]);
- }
-
- if (!BE (need_word_trtable, 0))
- {
- /* We don't care about whether the following character is a word
- character, or we are in a single-byte character set so we can
- discern by looking at the character code: allocate a
- 256-entry transition table. */
- trtable = state->trtable =
- (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
- if (BE (trtable == NULL, 0))
- goto out_free;
-
- /* For all characters ch...: */
- for (i = 0; i < BITSET_WORDS; ++i)
- for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
- elem;
- mask <<= 1, elem >>= 1, ++ch)
- if (BE (elem & 1, 0))
- {
- /* There must be exactly one destination which accepts
- character ch. See group_nodes_into_DFAstates. */
- for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
- ;
-
- /* j-th destination accepts the word character ch. */
- if (dfa->word_char[i] & mask)
- trtable[ch] = dest_states_word[j];
- else
- trtable[ch] = dest_states[j];
- }
- }
- else
- {
- /* We care about whether the following character is a word
- character, and we are in a multi-byte character set: discern
- by looking at the character code: build two 256-entry
- transition tables, one starting at trtable[0] and one
- starting at trtable[SBC_MAX]. */
- trtable = state->word_trtable =
- (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
- if (BE (trtable == NULL, 0))
- goto out_free;
-
- /* For all characters ch...: */
- for (i = 0; i < BITSET_WORDS; ++i)
- for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
- elem;
- mask <<= 1, elem >>= 1, ++ch)
- if (BE (elem & 1, 0))
- {
- /* There must be exactly one destination which accepts
- character ch. See group_nodes_into_DFAstates. */
- for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
- ;
-
- /* j-th destination accepts the word character ch. */
- trtable[ch] = dest_states[j];
- trtable[ch + SBC_MAX] = dest_states_word[j];
- }
- }
-
- /* new line */
- if (bitset_contain (acceptable, NEWLINE_CHAR))
- {
- /* The current state accepts newline character. */
- for (j = 0; j < ndests; ++j)
- if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
- {
- /* k-th destination accepts newline character. */
- trtable[NEWLINE_CHAR] = dest_states_nl[j];
- if (need_word_trtable)
- trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
- /* There must be only one destination which accepts
- newline. See group_nodes_into_DFAstates. */
- break;
- }
- }
-
- if (dest_states_malloced)
- free (dest_states);
-
- re_node_set_free (&follows);
- for (i = 0; i < ndests; ++i)
- re_node_set_free (dests_node + i);
-
- if (dests_node_malloced)
- free (dests_alloc);
-
- return true;
-}
-
-/* Group all nodes belonging to STATE into several destinations.
- Then for all destinations, set the nodes belonging to the destination
- to DESTS_NODE[i] and set the characters accepted by the destination
- to DEST_CH[i]. This function return the number of destinations. */
-
-static Idx
-internal_function
-group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
- re_node_set *dests_node, bitset_t *dests_ch)
-{
- reg_errcode_t err;
- bool ok;
- Idx i, j, k;
- Idx ndests; /* Number of the destinations from 'state'. */
- bitset_t accepts; /* Characters a node can accept. */
- const re_node_set *cur_nodes = &state->nodes;
- bitset_empty (accepts);
- ndests = 0;
-
- /* For all the nodes belonging to 'state', */
- for (i = 0; i < cur_nodes->nelem; ++i)
- {
- re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
- re_token_type_t type = node->type;
- unsigned int constraint = node->constraint;
-
- /* Enumerate all single byte character this node can accept. */
- if (type == CHARACTER)
- bitset_set (accepts, node->opr.c);
- else if (type == SIMPLE_BRACKET)
- {
- bitset_merge (accepts, node->opr.sbcset);
- }
- else if (type == OP_PERIOD)
- {
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- bitset_merge (accepts, dfa->sb_char);
- else
-#endif
- bitset_set_all (accepts);
- if (!(dfa->syntax & RE_DOT_NEWLINE))
- bitset_clear (accepts, '\n');
- if (dfa->syntax & RE_DOT_NOT_NULL)
- bitset_clear (accepts, '\0');
- }
-#ifdef RE_ENABLE_I18N
- else if (type == OP_UTF8_PERIOD)
- {
- if (ASCII_CHARS % BITSET_WORD_BITS == 0)
- memset (accepts, -1, ASCII_CHARS / CHAR_BIT);
- else
- bitset_merge (accepts, utf8_sb_map);
- if (!(dfa->syntax & RE_DOT_NEWLINE))
- bitset_clear (accepts, '\n');
- if (dfa->syntax & RE_DOT_NOT_NULL)
- bitset_clear (accepts, '\0');
- }
-#endif
- else
- continue;
-
- /* Check the 'accepts' and sift the characters which are not
- match it the context. */
- if (constraint)
- {
- if (constraint & NEXT_NEWLINE_CONSTRAINT)
- {
- bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
- bitset_empty (accepts);
- if (accepts_newline)
- bitset_set (accepts, NEWLINE_CHAR);
- else
- continue;
- }
- if (constraint & NEXT_ENDBUF_CONSTRAINT)
- {
- bitset_empty (accepts);
- continue;
- }
-
- if (constraint & NEXT_WORD_CONSTRAINT)
- {
- bitset_word_t any_set = 0;
- if (type == CHARACTER && !node->word_char)
- {
- bitset_empty (accepts);
- continue;
- }
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- for (j = 0; j < BITSET_WORDS; ++j)
- any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
- else
-#endif
- for (j = 0; j < BITSET_WORDS; ++j)
- any_set |= (accepts[j] &= dfa->word_char[j]);
- if (!any_set)
- continue;
- }
- if (constraint & NEXT_NOTWORD_CONSTRAINT)
- {
- bitset_word_t any_set = 0;
- if (type == CHARACTER && node->word_char)
- {
- bitset_empty (accepts);
- continue;
- }
-#ifdef RE_ENABLE_I18N
- if (dfa->mb_cur_max > 1)
- for (j = 0; j < BITSET_WORDS; ++j)
- any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
- else
-#endif
- for (j = 0; j < BITSET_WORDS; ++j)
- any_set |= (accepts[j] &= ~dfa->word_char[j]);
- if (!any_set)
- continue;
- }
- }
-
- /* Then divide 'accepts' into DFA states, or create a new
- state. Above, we make sure that accepts is not empty. */
- for (j = 0; j < ndests; ++j)
- {
- bitset_t intersec; /* Intersection sets, see below. */
- bitset_t remains;
- /* Flags, see below. */
- bitset_word_t has_intersec, not_subset, not_consumed;
-
- /* Optimization, skip if this state doesn't accept the character. */
- if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
- continue;
-
- /* Enumerate the intersection set of this state and 'accepts'. */
- has_intersec = 0;
- for (k = 0; k < BITSET_WORDS; ++k)
- has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
- /* And skip if the intersection set is empty. */
- if (!has_intersec)
- continue;
-
- /* Then check if this state is a subset of 'accepts'. */
- not_subset = not_consumed = 0;
- for (k = 0; k < BITSET_WORDS; ++k)
- {
- not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
- not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
- }
-
- /* If this state isn't a subset of 'accepts', create a
- new group state, which has the 'remains'. */
- if (not_subset)
- {
- bitset_copy (dests_ch[ndests], remains);
- bitset_copy (dests_ch[j], intersec);
- err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
- if (BE (err != REG_NOERROR, 0))
- goto error_return;
- ++ndests;
- }
-
- /* Put the position in the current group. */
- ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
- if (BE (! ok, 0))
- goto error_return;
-
- /* If all characters are consumed, go to next node. */
- if (!not_consumed)
- break;
- }
- /* Some characters remain, create a new group. */
- if (j == ndests)
- {
- bitset_copy (dests_ch[ndests], accepts);
- err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
- if (BE (err != REG_NOERROR, 0))
- goto error_return;
- ++ndests;
- bitset_empty (accepts);
- }
- }
- return ndests;
- error_return:
- for (j = 0; j < ndests; ++j)
- re_node_set_free (dests_node + j);
- return REG_MISSING;
-}
-
-#ifdef RE_ENABLE_I18N
-/* Check how many bytes the node 'dfa->nodes[node_idx]' accepts.
- Return the number of the bytes the node accepts.
- STR_IDX is the current index of the input string.
-
- This function handles the nodes which can accept one character, or
- one collating element like '.', '[a-z]', opposite to the other nodes
- can only accept one byte. */
-
-static int
-internal_function
-check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
- const re_string_t *input, Idx str_idx)
-{
- const re_token_t *node = dfa->nodes + node_idx;
- int char_len, elem_len;
- Idx i;
-
- if (BE (node->type == OP_UTF8_PERIOD, 0))
- {
- unsigned char c = re_string_byte_at (input, str_idx), d;
- if (BE (c < 0xc2, 1))
- return 0;
-
- if (str_idx + 2 > input->len)
- return 0;
-
- d = re_string_byte_at (input, str_idx + 1);
- if (c < 0xe0)
- return (d < 0x80 || d > 0xbf) ? 0 : 2;
- else if (c < 0xf0)
- {
- char_len = 3;
- if (c == 0xe0 && d < 0xa0)
- return 0;
- }
- else if (c < 0xf8)
- {
- char_len = 4;
- if (c == 0xf0 && d < 0x90)
- return 0;
- }
- else if (c < 0xfc)
- {
- char_len = 5;
- if (c == 0xf8 && d < 0x88)
- return 0;
- }
- else if (c < 0xfe)
- {
- char_len = 6;
- if (c == 0xfc && d < 0x84)
- return 0;
- }
- else
- return 0;
-
- if (str_idx + char_len > input->len)
- return 0;
-
- for (i = 1; i < char_len; ++i)
- {
- d = re_string_byte_at (input, str_idx + i);
- if (d < 0x80 || d > 0xbf)
- return 0;
- }
- return char_len;
- }
-
- char_len = re_string_char_size_at (input, str_idx);
- if (node->type == OP_PERIOD)
- {
- if (char_len <= 1)
- return 0;
- /* FIXME: I don't think this if is needed, as both '\n'
- and '\0' are char_len == 1. */
- /* '.' accepts any one character except the following two cases. */
- if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
- re_string_byte_at (input, str_idx) == '\n') ||
- ((dfa->syntax & RE_DOT_NOT_NULL) &&
- re_string_byte_at (input, str_idx) == '\0'))
- return 0;
- return char_len;
- }
-
- elem_len = re_string_elem_size_at (input, str_idx);
- if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
- return 0;
-
- if (node->type == COMPLEX_BRACKET)
- {
- const re_charset_t *cset = node->opr.mbcset;
-# ifdef _LIBC
- const unsigned char *pin
- = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
- Idx j;
- uint32_t nrules;
-# endif /* _LIBC */
- int match_len = 0;
- wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
- ? re_string_wchar_at (input, str_idx) : 0);
-
- /* match with multibyte character? */
- for (i = 0; i < cset->nmbchars; ++i)
- if (wc == cset->mbchars[i])
- {
- match_len = char_len;
- goto check_node_accept_bytes_match;
- }
- /* match with character_class? */
- for (i = 0; i < cset->nchar_classes; ++i)
- {
- wctype_t wt = cset->char_classes[i];
- if (__iswctype (wc, wt))
- {
- match_len = char_len;
- goto check_node_accept_bytes_match;
- }
- }
-
-# ifdef _LIBC
- nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
- if (nrules != 0)
- {
- unsigned int in_collseq = 0;
- const int32_t *table, *indirect;
- const unsigned char *weights, *extra;
- const char *collseqwc;
- /* This #include defines a local function! */
-# include <locale/weight.h>
-
- /* match with collating_symbol? */
- if (cset->ncoll_syms)
- extra = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
- for (i = 0; i < cset->ncoll_syms; ++i)
- {
- const unsigned char *coll_sym = extra + cset->coll_syms[i];
- /* Compare the length of input collating element and
- the length of current collating element. */
- if (*coll_sym != elem_len)
- continue;
- /* Compare each bytes. */
- for (j = 0; j < *coll_sym; j++)
- if (pin[j] != coll_sym[1 + j])
- break;
- if (j == *coll_sym)
- {
- /* Match if every bytes is equal. */
- match_len = j;
- goto check_node_accept_bytes_match;
- }
- }
-
- if (cset->nranges)
- {
- if (elem_len <= char_len)
- {
- collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
- in_collseq = __collseq_table_lookup (collseqwc, wc);
- }
- else
- in_collseq = find_collation_sequence_value (pin, elem_len);
- }
- /* match with range expression? */
- /* FIXME: Implement rational ranges here, too. */
- for (i = 0; i < cset->nranges; ++i)
- if (cset->range_starts[i] <= in_collseq
- && in_collseq <= cset->range_ends[i])
- {
- match_len = elem_len;
- goto check_node_accept_bytes_match;
- }
-
- /* match with equivalence_class? */
- if (cset->nequiv_classes)
- {
- const unsigned char *cp = pin;
- table = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
- weights = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
- extra = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
- indirect = (const int32_t *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
- int32_t idx = findidx (&cp, elem_len);
- if (idx > 0)
- for (i = 0; i < cset->nequiv_classes; ++i)
- {
- int32_t equiv_class_idx = cset->equiv_classes[i];
- size_t weight_len = weights[idx & 0xffffff];
- if (weight_len == weights[equiv_class_idx & 0xffffff]
- && (idx >> 24) == (equiv_class_idx >> 24))
- {
- Idx cnt = 0;
-
- idx &= 0xffffff;
- equiv_class_idx &= 0xffffff;
-
- while (cnt <= weight_len
- && (weights[equiv_class_idx + 1 + cnt]
- == weights[idx + 1 + cnt]))
- ++cnt;
- if (cnt > weight_len)
- {
- match_len = elem_len;
- goto check_node_accept_bytes_match;
- }
- }
- }
- }
- }
- else
-# endif /* _LIBC */
- {
- /* match with range expression? */
- for (i = 0; i < cset->nranges; ++i)
- {
- if (cset->range_starts[i] <= wc && wc <= cset->range_ends[i])
- {
- match_len = char_len;
- goto check_node_accept_bytes_match;
- }
- }
- }
- check_node_accept_bytes_match:
- if (!cset->non_match)
- return match_len;
- else
- {
- if (match_len > 0)
- return 0;
- else
- return (elem_len > char_len) ? elem_len : char_len;
- }
- }
- return 0;
-}
-
-# ifdef _LIBC
-static unsigned int
-internal_function
-find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
-{
- uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
- if (nrules == 0)
- {
- if (mbs_len == 1)
- {
- /* No valid character. Match it as a single byte character. */
- const unsigned char *collseq = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
- return collseq[mbs[0]];
- }
- return UINT_MAX;
- }
- else
- {
- int32_t idx;
- const unsigned char *extra = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
- int32_t extrasize = (const unsigned char *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
-
- for (idx = 0; idx < extrasize;)
- {
- int mbs_cnt;
- bool found = false;
- int32_t elem_mbs_len;
- /* Skip the name of collating element name. */
- idx = idx + extra[idx] + 1;
- elem_mbs_len = extra[idx++];
- if (mbs_len == elem_mbs_len)
- {
- for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
- if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
- break;
- if (mbs_cnt == elem_mbs_len)
- /* Found the entry. */
- found = true;
- }
- /* Skip the byte sequence of the collating element. */
- idx += elem_mbs_len;
- /* Adjust for the alignment. */
- idx = (idx + 3) & ~3;
- /* Skip the collation sequence value. */
- idx += sizeof (uint32_t);
- /* Skip the wide char sequence of the collating element. */
- idx = idx + sizeof (uint32_t) * (*(int32_t *) (extra + idx) + 1);
- /* If we found the entry, return the sequence value. */
- if (found)
- return *(uint32_t *) (extra + idx);
- /* Skip the collation sequence value. */
- idx += sizeof (uint32_t);
- }
- return UINT_MAX;
- }
-}
-# endif /* _LIBC */
-#endif /* RE_ENABLE_I18N */
-
-/* Check whether the node accepts the byte which is IDX-th
- byte of the INPUT. */
-
-static bool
-internal_function
-check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
- Idx idx)
-{
- unsigned char ch;
- ch = re_string_byte_at (&mctx->input, idx);
- switch (node->type)
- {
- case CHARACTER:
- if (node->opr.c != ch)
- return false;
- break;
-
- case SIMPLE_BRACKET:
- if (!bitset_contain (node->opr.sbcset, ch))
- return false;
- break;
-
-#ifdef RE_ENABLE_I18N
- case OP_UTF8_PERIOD:
- if (ch >= ASCII_CHARS)
- return false;
- /* FALLTHROUGH */
-#endif
- case OP_PERIOD:
- if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
- || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
- return false;
- break;
-
- default:
- return false;
- }
-
- if (node->constraint)
- {
- /* The node has constraints. Check whether the current context
- satisfies the constraints. */
- unsigned int context = re_string_context_at (&mctx->input, idx,
- mctx->eflags);
- if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
- return false;
- }
-
- return true;
-}
-
-/* Extend the buffers, if the buffers have run out. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-extend_buffers (re_match_context_t *mctx, int min_len)
-{
- reg_errcode_t ret;
- re_string_t *pstr = &mctx->input;
-
- /* Avoid overflow. */
- if (BE (MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *)) / 2
- <= pstr->bufs_len, 0))
- return REG_ESPACE;
-
- /* Double the lengths of the buffers, but allocate at least MIN_LEN. */
- ret = re_string_realloc_buffers (pstr,
- MAX (min_len,
- MIN (pstr->len, pstr->bufs_len * 2)));
- if (BE (ret != REG_NOERROR, 0))
- return ret;
-
- if (mctx->state_log != NULL)
- {
- /* And double the length of state_log. */
- /* XXX We have no indication of the size of this buffer. If this
- allocation fail we have no indication that the state_log array
- does not have the right size. */
- re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
- pstr->bufs_len + 1);
- if (BE (new_array == NULL, 0))
- return REG_ESPACE;
- mctx->state_log = new_array;
- }
-
- /* Then reconstruct the buffers. */
- if (pstr->icase)
- {
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- {
- ret = build_wcs_upper_buffer (pstr);
- if (BE (ret != REG_NOERROR, 0))
- return ret;
- }
- else
-#endif /* RE_ENABLE_I18N */
- build_upper_buffer (pstr);
- }
- else
- {
-#ifdef RE_ENABLE_I18N
- if (pstr->mb_cur_max > 1)
- build_wcs_buffer (pstr);
- else
-#endif /* RE_ENABLE_I18N */
- {
- if (pstr->trans != NULL)
- re_string_translate_buffer (pstr);
- }
- }
- return REG_NOERROR;
-}
-
-
-/* Functions for matching context. */
-
-/* Initialize MCTX. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-match_ctx_init (re_match_context_t *mctx, int eflags, Idx n)
-{
- mctx->eflags = eflags;
- mctx->match_last = REG_MISSING;
- if (n > 0)
- {
- /* Avoid overflow. */
- size_t max_object_size =
- MAX (sizeof (struct re_backref_cache_entry),
- sizeof (re_sub_match_top_t *));
- if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < n, 0))
- return REG_ESPACE;
-
- mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
- mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
- if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
- return REG_ESPACE;
- }
- /* Already zero-ed by the caller.
- else
- mctx->bkref_ents = NULL;
- mctx->nbkref_ents = 0;
- mctx->nsub_tops = 0; */
- mctx->abkref_ents = n;
- mctx->max_mb_elem_len = 1;
- mctx->asub_tops = n;
- return REG_NOERROR;
-}
-
-/* Clean the entries which depend on the current input in MCTX.
- This function must be invoked when the matcher changes the start index
- of the input, or changes the input string. */
-
-static void
-internal_function
-match_ctx_clean (re_match_context_t *mctx)
-{
- Idx st_idx;
- for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
- {
- Idx sl_idx;
- re_sub_match_top_t *top = mctx->sub_tops[st_idx];
- for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
- {
- re_sub_match_last_t *last = top->lasts[sl_idx];
- re_free (last->path.array);
- re_free (last);
- }
- re_free (top->lasts);
- if (top->path)
- {
- re_free (top->path->array);
- re_free (top->path);
- }
- free (top);
- }
-
- mctx->nsub_tops = 0;
- mctx->nbkref_ents = 0;
-}
-
-/* Free all the memory associated with MCTX. */
-
-static void
-internal_function
-match_ctx_free (re_match_context_t *mctx)
-{
- /* First, free all the memory associated with MCTX->SUB_TOPS. */
- match_ctx_clean (mctx);
- re_free (mctx->sub_tops);
- re_free (mctx->bkref_ents);
-}
-
-/* Add a new backreference entry to MCTX.
- Note that we assume that caller never call this function with duplicate
- entry, and call with STR_IDX which isn't smaller than any existing entry.
-*/
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Idx from,
- Idx to)
-{
- if (mctx->nbkref_ents >= mctx->abkref_ents)
- {
- struct re_backref_cache_entry* new_entry;
- new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
- mctx->abkref_ents * 2);
- if (BE (new_entry == NULL, 0))
- {
- re_free (mctx->bkref_ents);
- return REG_ESPACE;
- }
- mctx->bkref_ents = new_entry;
- memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
- sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
- mctx->abkref_ents *= 2;
- }
- if (mctx->nbkref_ents > 0
- && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
- mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
-
- mctx->bkref_ents[mctx->nbkref_ents].node = node;
- mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
- mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
- mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
-
- /* This is a cache that saves negative results of check_dst_limits_calc_pos.
- If bit N is clear, means that this entry won't epsilon-transition to
- an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
- it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
- such node.
-
- A backreference does not epsilon-transition unless it is empty, so set
- to all zeros if FROM != TO. */
- mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
- = (from == to ? -1 : 0);
-
- mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
- if (mctx->max_mb_elem_len < to - from)
- mctx->max_mb_elem_len = to - from;
- return REG_NOERROR;
-}
-
-/* Return the first entry with the same str_idx, or REG_MISSING if none is
- found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
-
-static Idx
-internal_function
-search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx)
-{
- Idx left, right, mid, last;
- last = right = mctx->nbkref_ents;
- for (left = 0; left < right;)
- {
- mid = (left + right) / 2;
- if (mctx->bkref_ents[mid].str_idx < str_idx)
- left = mid + 1;
- else
- right = mid;
- }
- if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
- return left;
- else
- return REG_MISSING;
-}
-
-/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
- at STR_IDX. */
-
-static reg_errcode_t
-internal_function __attribute_warn_unused_result__
-match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx)
-{
-#ifdef DEBUG
- assert (mctx->sub_tops != NULL);
- assert (mctx->asub_tops > 0);
-#endif
- if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
- {
- Idx new_asub_tops = mctx->asub_tops * 2;
- re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
- re_sub_match_top_t *,
- new_asub_tops);
- if (BE (new_array == NULL, 0))
- return REG_ESPACE;
- mctx->sub_tops = new_array;
- mctx->asub_tops = new_asub_tops;
- }
- mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
- if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
- return REG_ESPACE;
- mctx->sub_tops[mctx->nsub_tops]->node = node;
- mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
- return REG_NOERROR;
-}
-
-/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
- at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
-
-static re_sub_match_last_t *
-internal_function
-match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx)
-{
- re_sub_match_last_t *new_entry;
- if (BE (subtop->nlasts == subtop->alasts, 0))
- {
- Idx new_alasts = 2 * subtop->alasts + 1;
- re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
- re_sub_match_last_t *,
- new_alasts);
- if (BE (new_array == NULL, 0))
- return NULL;
- subtop->lasts = new_array;
- subtop->alasts = new_alasts;
- }
- new_entry = calloc (1, sizeof (re_sub_match_last_t));
- if (BE (new_entry != NULL, 1))
- {
- subtop->lasts[subtop->nlasts] = new_entry;
- new_entry->node = node;
- new_entry->str_idx = str_idx;
- ++subtop->nlasts;
- }
- return new_entry;
-}
-
-static void
-internal_function
-sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
- re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx)
-{
- sctx->sifted_states = sifted_sts;
- sctx->limited_states = limited_sts;
- sctx->last_node = last_node;
- sctx->last_str_idx = last_str_idx;
- re_node_set_init_empty (&sctx->limits);
-}
diff --git a/contrib/tools/bison/lib/spawn_int.h b/contrib/tools/bison/lib/spawn_int.h
deleted file mode 100644
index f22a659fbe..0000000000
--- a/contrib/tools/bison/lib/spawn_int.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2000, 2008-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <sys/types.h>
-
-/* Data structure to contain the action information. */
-struct __spawn_action
-{
- enum
- {
- spawn_do_close,
- spawn_do_dup2,
- spawn_do_open
- } tag;
-
- union
- {
- struct
- {
- int fd;
- } close_action;
- struct
- {
- int fd;
- int newfd;
- } dup2_action;
- struct
- {
- int fd;
- const char *path;
- int oflag;
- mode_t mode;
- } open_action;
- } action;
-};
-
-#if !_LIBC
-# define __posix_spawn_file_actions_realloc gl_posix_spawn_file_actions_realloc
-#endif
-extern int __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *
- file_actions);
-
-#if !_LIBC
-# define __spawni gl_posix_spawn_internal
-#endif
-extern int __spawni (pid_t *pid, const char *path,
- const posix_spawn_file_actions_t *file_actions,
- const posix_spawnattr_t *attrp, char *const argv[],
- char *const envp[], int use_path);
diff --git a/contrib/tools/bison/lib/spawni.c b/contrib/tools/bison/lib/spawni.c
deleted file mode 100644
index e2f7b45b60..0000000000
--- a/contrib/tools/bison/lib/spawni.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/* Guts of POSIX spawn interface. Generic POSIX.1 version.
- Copyright (C) 2000-2006, 2008-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-/* Specification. */
-#include <spawn.h>
-#include "spawn_int.h"
-
-#include "palloca.h"
-#include <errno.h>
-
-#include <fcntl.h>
-#ifndef O_LARGEFILE
-# define O_LARGEFILE 0
-#endif
-
-#if _LIBC || HAVE_PATHS_H
-# include <paths.h>
-#else
-# define _PATH_BSHELL "/bin/sh"
-#endif
-
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#if _LIBC
-# include <not-cancel.h>
-#else
-# define close_not_cancel close
-# define open_not_cancel open
-#endif
-
-#if _LIBC
-# include <local-setxid.h>
-#else
-# if !HAVE_SETEUID
-# define seteuid(id) setresuid (-1, id, -1)
-# endif
-# if !HAVE_SETEGID
-# define setegid(id) setresgid (-1, id, -1)
-# endif
-# define local_seteuid(id) seteuid (id)
-# define local_setegid(id) setegid (id)
-#endif
-
-#if _LIBC
-# define alloca __alloca
-# define execve __execve
-# define dup2 __dup2
-# define fork __fork
-# define getgid __getgid
-# define getuid __getuid
-# define sched_setparam __sched_setparam
-# define sched_setscheduler __sched_setscheduler
-# define setpgid __setpgid
-# define sigaction __sigaction
-# define sigismember __sigismember
-# define sigprocmask __sigprocmask
-# define strchrnul __strchrnul
-# define vfork __vfork
-#else
-# undef internal_function
-# define internal_function /* empty */
-#endif
-
-
-/* The Unix standard contains a long explanation of the way to signal
- an error after the fork() was successful. Since no new wait status
- was wanted there is no way to signal an error using one of the
- available methods. The committee chose to signal an error by a
- normal program exit with the exit code 127. */
-#define SPAWN_ERROR 127
-
-
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-
-/* Native Windows API. */
-int
-__spawni (pid_t *pid, const char *file,
- const posix_spawn_file_actions_t *file_actions,
- const posix_spawnattr_t *attrp, char *const argv[],
- char *const envp[], int use_path)
-{
- /* Not yet implemented. */
- return ENOSYS;
-}
-
-#else
-
-
-/* The file is accessible but it is not an executable file. Invoke
- the shell to interpret it as a script. */
-static void
-internal_function
-script_execute (const char *file, char *const argv[], char *const envp[])
-{
- /* Count the arguments. */
- int argc = 0;
- while (argv[argc++])
- ;
-
- /* Construct an argument list for the shell. */
- {
- char **new_argv = (char **) alloca ((argc + 1) * sizeof (char *));
- new_argv[0] = (char *) _PATH_BSHELL;
- new_argv[1] = (char *) file;
- while (argc > 1)
- {
- new_argv[argc] = argv[argc - 1];
- --argc;
- }
-
- /* Execute the shell. */
- execve (new_argv[0], new_argv, envp);
- }
-}
-
-
-/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
- Before running the process perform the actions described in FILE-ACTIONS. */
-int
-__spawni (pid_t *pid, const char *file,
- const posix_spawn_file_actions_t *file_actions,
- const posix_spawnattr_t *attrp, char *const argv[],
- char *const envp[], int use_path)
-{
- pid_t new_pid;
- char *path, *p, *name;
- size_t len;
- size_t pathlen;
-
- /* Do this once. */
- short int flags = attrp == NULL ? 0 : attrp->_flags;
-
- /* Avoid gcc warning
- "variable 'flags' might be clobbered by 'longjmp' or 'vfork'" */
- (void) &flags;
-
- /* Generate the new process. */
-#if HAVE_VFORK
- if ((flags & POSIX_SPAWN_USEVFORK) != 0
- /* If no major work is done, allow using vfork. Note that we
- might perform the path searching. But this would be done by
- a call to execvp(), too, and such a call must be OK according
- to POSIX. */
- || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
- | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
- | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
- && file_actions == NULL))
- new_pid = vfork ();
- else
-#endif
- new_pid = fork ();
-
- if (new_pid != 0)
- {
- if (new_pid < 0)
- return errno;
-
- /* The call was successful. Store the PID if necessary. */
- if (pid != NULL)
- *pid = new_pid;
-
- return 0;
- }
-
- /* Set signal mask. */
- if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
- && sigprocmask (SIG_SETMASK, &attrp->_ss, NULL) != 0)
- _exit (SPAWN_ERROR);
-
- /* Set signal default action. */
- if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
- {
- /* We have to iterate over all signals. This could possibly be
- done better but it requires system specific solutions since
- the sigset_t data type can be very different on different
- architectures. */
- int sig;
- struct sigaction sa;
-
- memset (&sa, '\0', sizeof (sa));
- sa.sa_handler = SIG_DFL;
-
- for (sig = 1; sig <= NSIG; ++sig)
- if (sigismember (&attrp->_sd, sig) != 0
- && sigaction (sig, &sa, NULL) != 0)
- _exit (SPAWN_ERROR);
-
- }
-
-#if (_LIBC ? defined _POSIX_PRIORITY_SCHEDULING : HAVE_SCHED_SETPARAM && HAVE_SCHED_SETSCHEDULER)
- /* Set the scheduling algorithm and parameters. */
- if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
- == POSIX_SPAWN_SETSCHEDPARAM)
- {
- if (sched_setparam (0, &attrp->_sp) == -1)
- _exit (SPAWN_ERROR);
- }
- else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
- {
- if (sched_setscheduler (0, attrp->_policy,
- (flags & POSIX_SPAWN_SETSCHEDPARAM) != 0
- ? &attrp->_sp : NULL) == -1)
- _exit (SPAWN_ERROR);
- }
-#endif
-
- /* Set the process group ID. */
- if ((flags & POSIX_SPAWN_SETPGROUP) != 0
- && setpgid (0, attrp->_pgrp) != 0)
- _exit (SPAWN_ERROR);
-
- /* Set the effective user and group IDs. */
- if ((flags & POSIX_SPAWN_RESETIDS) != 0
- && (local_seteuid (getuid ()) != 0
- || local_setegid (getgid ()) != 0))
- _exit (SPAWN_ERROR);
-
- /* Execute the file actions. */
- if (file_actions != NULL)
- {
- int cnt;
-
- for (cnt = 0; cnt < file_actions->_used; ++cnt)
- {
- struct __spawn_action *action = &file_actions->_actions[cnt];
-
- switch (action->tag)
- {
- case spawn_do_close:
- if (close_not_cancel (action->action.close_action.fd) != 0)
- /* Signal the error. */
- _exit (SPAWN_ERROR);
- break;
-
- case spawn_do_open:
- {
- int new_fd = open_not_cancel (action->action.open_action.path,
- action->action.open_action.oflag
- | O_LARGEFILE,
- action->action.open_action.mode);
-
- if (new_fd == -1)
- /* The 'open' call failed. */
- _exit (SPAWN_ERROR);
-
- /* Make sure the desired file descriptor is used. */
- if (new_fd != action->action.open_action.fd)
- {
- if (dup2 (new_fd, action->action.open_action.fd)
- != action->action.open_action.fd)
- /* The 'dup2' call failed. */
- _exit (SPAWN_ERROR);
-
- if (close_not_cancel (new_fd) != 0)
- /* The 'close' call failed. */
- _exit (SPAWN_ERROR);
- }
- }
- break;
-
- case spawn_do_dup2:
- if (dup2 (action->action.dup2_action.fd,
- action->action.dup2_action.newfd)
- != action->action.dup2_action.newfd)
- /* The 'dup2' call failed. */
- _exit (SPAWN_ERROR);
- break;
- }
- }
- }
-
- if (! use_path || strchr (file, '/') != NULL)
- {
- /* The FILE parameter is actually a path. */
- execve (file, argv, envp);
-
- if (errno == ENOEXEC)
- script_execute (file, argv, envp);
-
- /* Oh, oh. 'execve' returns. This is bad. */
- _exit (SPAWN_ERROR);
- }
-
- /* We have to search for FILE on the path. */
- path = getenv ("PATH");
- if (path == NULL)
- {
-#if HAVE_CONFSTR
- /* There is no 'PATH' in the environment.
- The default search path is the current directory
- followed by the path 'confstr' returns for '_CS_PATH'. */
- len = confstr (_CS_PATH, (char *) NULL, 0);
- path = (char *) alloca (1 + len);
- path[0] = ':';
- (void) confstr (_CS_PATH, path + 1, len);
-#else
- /* Pretend that the PATH contains only the current directory. */
- path = "";
-#endif
- }
-
- len = strlen (file) + 1;
- pathlen = strlen (path);
- name = alloca (pathlen + len + 1);
- /* Copy the file name at the top. */
- name = (char *) memcpy (name + pathlen + 1, file, len);
- /* And add the slash. */
- *--name = '/';
-
- p = path;
- do
- {
- char *startp;
-
- path = p;
- p = strchrnul (path, ':');
-
- if (p == path)
- /* Two adjacent colons, or a colon at the beginning or the end
- of 'PATH' means to search the current directory. */
- startp = name + 1;
- else
- startp = (char *) memcpy (name - (p - path), path, p - path);
-
- /* Try to execute this name. If it works, execv will not return. */
- execve (startp, argv, envp);
-
- if (errno == ENOEXEC)
- script_execute (startp, argv, envp);
-
- switch (errno)
- {
- case EACCES:
- case ENOENT:
- case ESTALE:
- case ENOTDIR:
- /* Those errors indicate the file is missing or not executable
- by us, in which case we want to just try the next path
- directory. */
- break;
-
- default:
- /* Some other error means we found an executable file, but
- something went wrong executing it; return the error to our
- caller. */
- _exit (SPAWN_ERROR);
- }
- }
- while (*p++ != '\0');
-
- /* Return with an error. */
- _exit (SPAWN_ERROR);
-}
-
-#endif
diff --git a/contrib/tools/bison/lib/spawnp.c b/contrib/tools/bison/lib/spawnp.c
deleted file mode 100644
index 8bc5f99aca..0000000000
--- a/contrib/tools/bison/lib/spawnp.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (C) 2000, 2009-2013 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-/* Specification. */
-#include <spawn.h>
-
-#include "spawn_int.h"
-
-/* Spawn a new process executing FILE with the attributes describes in *ATTRP.
- Before running the process perform the actions described in FILE-ACTIONS. */
-int
-posix_spawnp (pid_t *pid, const char *file,
- const posix_spawn_file_actions_t *file_actions,
- const posix_spawnattr_t *attrp, char *const argv[],
- char *const envp[])
-{
- return __spawni (pid, file, file_actions, attrp, argv, envp, 1);
-}
diff --git a/contrib/tools/bison/lib/tmpdir.c b/contrib/tools/bison/lib/tmpdir.c
deleted file mode 100644
index 1b3fb023a0..0000000000
--- a/contrib/tools/bison/lib/tmpdir.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Copyright (C) 1999, 2001-2002, 2006, 2009-2013 Free Software Foundation,
- Inc.
- This file is part of the GNU C Library.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Extracted from sysdeps/posix/tempname.c. */
-
-#include <config.h>
-
-/* Specification. */
-#include "tmpdir.h"
-
-#include <stdbool.h>
-#include "stdlib--.h"
-#include <string.h>
-
-#include <errno.h>
-#ifndef __set_errno
-# define __set_errno(Val) errno = (Val)
-#endif
-
-#include <stdio.h>
-#ifndef P_tmpdir
-# ifdef _P_tmpdir /* native Windows */
-# define P_tmpdir _P_tmpdir
-# else
-# define P_tmpdir "/tmp"
-# endif
-#endif
-
-#include <sys/stat.h>
-
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-# define WIN32_LEAN_AND_MEAN /* avoid including junk */
-# include <windows.h>
-#endif
-
-#include "pathmax.h"
-
-#if _LIBC
-# define struct_stat64 struct stat64
-#else
-# define struct_stat64 struct stat
-# define __libc_secure_getenv secure_getenv
-# define __xstat64(version, path, buf) stat (path, buf)
-#endif
-
-/* Pathname support.
- ISSLASH(C) tests whether C is a directory separator character.
- */
-#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
- /* Native Windows, Cygwin, OS/2, DOS */
-# define ISSLASH(C) ((C) == '/' || (C) == '\\')
-#else
- /* Unix */
-# define ISSLASH(C) ((C) == '/')
-#endif
-
-
-/* Return nonzero if DIR is an existent directory. */
-static bool
-direxists (const char *dir)
-{
- struct_stat64 buf;
- return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
-}
-
-/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
- non-null and exists, uses it; otherwise uses the first of $TMPDIR,
- P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
- for use with mk[s]temp. Will fail (-1) if DIR is non-null and
- doesn't exist, none of the searched dirs exists, or there's not
- enough space in TMPL. */
-int
-path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
- bool try_tmpdir)
-{
- const char *d;
- size_t dlen, plen;
- bool add_slash;
-
- if (!pfx || !pfx[0])
- {
- pfx = "file";
- plen = 4;
- }
- else
- {
- plen = strlen (pfx);
- if (plen > 5)
- plen = 5;
- }
-
- if (try_tmpdir)
- {
- d = __libc_secure_getenv ("TMPDIR");
- if (d != NULL && direxists (d))
- dir = d;
- else if (dir != NULL && direxists (dir))
- /* nothing */ ;
- else
- dir = NULL;
- }
- if (dir == NULL)
- {
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
- char dirbuf[PATH_MAX];
- DWORD retval;
-
- /* Find Windows temporary file directory.
- We try this before P_tmpdir because Windows defines P_tmpdir to "\\"
- and will therefore try to put all temporary files in the root
- directory (unless $TMPDIR is set). */
- retval = GetTempPath (PATH_MAX, dirbuf);
- if (retval > 0 && retval < PATH_MAX && direxists (dirbuf))
- dir = dirbuf;
- else
-#endif
- if (direxists (P_tmpdir))
- dir = P_tmpdir;
- else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
- dir = "/tmp";
- else
- {
- __set_errno (ENOENT);
- return -1;
- }
- }
-
- dlen = strlen (dir);
-#ifdef __VMS
- add_slash = 0;
-#else
- add_slash = dlen != 0 && !ISSLASH (dir[dlen - 1]);
-#endif
-
- /* check we have room for "${dir}/${pfx}XXXXXX\0" */
- if (tmpl_len < dlen + add_slash + plen + 6 + 1)
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- memcpy (tmpl, dir, dlen);
- sprintf (tmpl + dlen, &"/%.*sXXXXXX"[!add_slash], (int) plen, pfx);
- return 0;
-}
diff --git a/contrib/tools/bison/lib/tmpdir.h b/contrib/tools/bison/lib/tmpdir.h
deleted file mode 100644
index ff7c70f346..0000000000
--- a/contrib/tools/bison/lib/tmpdir.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Determine a temporary directory.
- Copyright (C) 2001-2002, 2009-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
- non-null and exists, uses it; otherwise uses the first of $TMPDIR,
- P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
- for use with mk[s]temp. Will fail (-1) if DIR is non-null and
- doesn't exist, none of the searched dirs exists, or there's not
- enough space in TMPL. */
-extern int path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, bool try_tmpdir);
diff --git a/contrib/tools/bison/lib/verror.c b/contrib/tools/bison/lib/verror.c
deleted file mode 100644
index 5f899c1b7a..0000000000
--- a/contrib/tools/bison/lib/verror.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* va_list error handler for noninteractive utilities
- Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Written by Eric Blake. */
-
-#include <config.h>
-
-#include "verror.h"
-#include "xvasprintf.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#if ENABLE_NLS
-# include "gettext.h"
-# define _(msgid) gettext (msgid)
-#endif
-
-#ifndef _
-# define _(String) String
-#endif
-
-/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
- if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
- If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
- Use the globals error_print_progname and error_message_count similarly
- to error(). */
-void
-verror (int status, int errnum, const char *format, va_list args)
-{
- verror_at_line (status, errnum, NULL, 0, format, args);
-}
-
-/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
- if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
- If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
- If FNAME is not NULL, prepend the message with "FNAME:LINENO:".
- Use the globals error_print_progname, error_message_count, and
- error_one_per_line similarly to error_at_line(). */
-void
-verror_at_line (int status, int errnum, const char *file,
- unsigned int line_number, const char *format, va_list args)
-{
- char *message = xvasprintf (format, args);
- if (message)
- {
- /* Until http://sourceware.org/bugzilla/show_bug.cgi?id=2997 is fixed,
- glibc violates GNU Coding Standards when the file argument to
- error_at_line is NULL. */
- if (file)
- error_at_line (status, errnum, file, line_number, "%s", message);
- else
- error (status, errnum, "%s", message);
- }
- else
- {
- /* EOVERFLOW, EINVAL, and EILSEQ from xvasprintf are signs of
- serious programmer errors. */
- error (0, errno, _("unable to display error message"));
- abort ();
- }
- free (message);
-}
diff --git a/contrib/tools/bison/lib/verror.h b/contrib/tools/bison/lib/verror.h
deleted file mode 100644
index 7e7284ad82..0000000000
--- a/contrib/tools/bison/lib/verror.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Declaration for va_list error-reporting function
- Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef _VERROR_H
-#define _VERROR_H 1
-
-#include <stdarg.h>
-
-#include "error.h" /* for _GL_ATTRIBUTE_FORMAT */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
- if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
- If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
- Use the globals error_print_progname and error_message_count similarly
- to error(). */
-
-extern void verror (int __status, int __errnum, const char *__format,
- va_list __args)
- _GL_ATTRIBUTE_FORMAT ((__printf__, 3, 0));
-
-/* Print a message with 'vfprintf (stderr, FORMAT, ARGS)';
- if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
- If STATUS is nonzero, terminate the program with 'exit (STATUS)'.
- If FNAME is not NULL, prepend the message with "FNAME:LINENO:".
- Use the globals error_print_progname, error_message_count, and
- error_one_per_line similarly to error_at_line(). */
-
-extern void verror_at_line (int __status, int __errnum, const char *__fname,
- unsigned int __lineno, const char *__format,
- va_list __args)
- _GL_ATTRIBUTE_FORMAT ((__printf__, 5, 0));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* verror.h */
diff --git a/contrib/tools/bison/lib/ya.make b/contrib/tools/bison/lib/ya.make
index 74520fe268..23f9804554 100644
--- a/contrib/tools/bison/lib/ya.make
+++ b/contrib/tools/bison/lib/ya.make
@@ -93,7 +93,6 @@ SRCS(
malloca.c
mbswidth.c
mbrtowc.c
- memchr2.c
mkstemp-safer.c
nl_langinfo.c
pipe-safer.c
@@ -107,8 +106,6 @@ SRCS(
raise.c
rawmemchr.c
readlink.c
- realloc.c
- regex.c
rename.c
rmdir.c
secure_getenv.c
@@ -121,11 +118,9 @@ SRCS(
stripslash.c
tempname.c
timevar.c
- tmpdir.c
unistd.c
vasnprintf.c
vbitset.c
- verror.c
wait-process.c
wctype-h.c
xalloc-die.c
@@ -169,7 +164,6 @@ IF (OS_WINDOWS)
fseeko.c
fopen.c
ftello.c
- gettimeofday.c
localeconv.c
msvc-inval.c
msvc-nothrow.c
@@ -177,8 +171,6 @@ IF (OS_WINDOWS)
sigaction.c
sigprocmask.c
snprintf.c
- spawni.c
- spawnp.c
strndup.c
waitpid.c
wcwidth.c