diff options
Diffstat (limited to 'posix/regex_internal.c')
-rw-r--r-- | posix/regex_internal.c | 1095 |
1 files changed, 1095 insertions, 0 deletions
diff --git a/posix/regex_internal.c b/posix/regex_internal.c new file mode 100644 index 0000000000..63bed420cd --- /dev/null +++ b/posix/regex_internal.c @@ -0,0 +1,1095 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002 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 Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#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 || defined _LIBC +# include <libintl.h> +# ifdef _LIBC +# undef gettext +# define gettext(msgid) __dcgettext ("libc", 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 + +#include "regex.h" +#include "regex_internal.h" + +static void re_string_construct_common (const unsigned char *str, + int len, re_string_t *pstr); +#ifdef RE_ENABLE_I18N +static reg_errcode_t build_wcs_buffer (re_string_t *pstr); +static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr); +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t build_upper_buffer (re_string_t *pstr); +static reg_errcode_t re_string_translate_buffer (re_string_t *pstr, + RE_TRANSLATE_TYPE trans); +static re_dfastate_t *create_newstate_common (re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int hash); +static re_dfastate_t *create_ci_newstate (re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int hash); +static re_dfastate_t *create_cd_newstate (re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int context, + unsigned int hash); +static unsigned int inline calc_state_hash (const re_node_set *nodes, + unsigned int context); + +/* Functions for string operation. */ + +/* Construct string object. */ +static reg_errcode_t +re_string_construct (pstr, str, len, trans) + re_string_t *pstr; + const unsigned char *str; + int len; + RE_TRANSLATE_TYPE trans; +{ + reg_errcode_t ret; + re_string_construct_common (str, len, pstr); +#ifdef RE_ENABLE_I18N + if (MB_CUR_MAX >1 && pstr->len > 0) + { + ret = build_wcs_buffer (pstr); + if (ret != REG_NOERROR) + return ret; + } +#endif /* RE_ENABLE_I18N */ + pstr->mbs_case = str; + if (trans != NULL) + { + ret = re_string_translate_buffer (pstr, trans); + if (ret != REG_NOERROR) + return ret; + } + return REG_NOERROR; +} + +/* Construct string object. We use this function instead of + re_string_construct for case insensitive mode. */ + +static reg_errcode_t +re_string_construct_toupper (pstr, str, len, trans) + re_string_t *pstr; + const unsigned char *str; + int len; + RE_TRANSLATE_TYPE trans; +{ + reg_errcode_t ret; + /* Set case sensitive buffer. */ + re_string_construct_common (str, len, pstr); +#ifdef RE_ENABLE_I18N + if (MB_CUR_MAX >1) + { + if (pstr->len > 0) + { + ret = build_wcs_upper_buffer (pstr); + if (ret != REG_NOERROR) + return ret; + } + } + else +#endif /* RE_ENABLE_I18N */ + { + if (pstr->len > 0) + { + ret = build_upper_buffer (pstr); + if (ret != REG_NOERROR) + return ret; + } + } + pstr->mbs_case = str; + if (trans != NULL) + { + ret = re_string_translate_buffer (pstr, trans); + if (ret != REG_NOERROR) + return ret; + } + return REG_NOERROR; +} + +/* Helper functions for re_string_construct_*. */ +static void +re_string_construct_common (str, len, pstr) + const unsigned char *str; + int len; + re_string_t *pstr; +{ + pstr->mbs = str; + pstr->cur_idx = 0; + pstr->len = len; +#ifdef RE_ENABLE_I18N + pstr->wcs = NULL; +#endif + pstr->mbs_case = NULL; + pstr->mbs_alloc = 0; + pstr->mbs_case_alloc = 0; +} + +#ifdef RE_ENABLE_I18N + +/* Build wide character buffer for `pstr'. + 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. */ + +static reg_errcode_t +build_wcs_buffer (pstr) + re_string_t *pstr; +{ + mbstate_t state, prev_st; + wchar_t wc; + int char_idx, char_len, mbclen; + + pstr->wcs = re_malloc (wchar_t, pstr->len + 1); + if (pstr->wcs == NULL) + return REG_ESPACE; + + memset (&state, '\0', sizeof (mbstate_t)); + char_len = pstr->len; + for (char_idx = 0; char_idx < char_len ;) + { + int next_idx, remain_len = char_len - char_idx; + prev_st = state; + mbclen = mbrtowc (&wc, pstr->mbs + char_idx, remain_len, &state); + if (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0) + /* We treat these cases as a singlebyte character. */ + { + mbclen = 1; + wc = (wchar_t) pstr->mbs[char_idx++]; + state = prev_st; + } + /* Write wide character and padding. */ + pstr->wcs[char_idx++] = wc; + for (next_idx = char_idx + mbclen - 1; char_idx < next_idx ;) + pstr->wcs[char_idx++] = WEOF; + } + return REG_NOERROR; +} + +static reg_errcode_t +build_wcs_upper_buffer (pstr) + re_string_t *pstr; +{ + mbstate_t state, prev_st; + wchar_t wc; + unsigned char *mbs_upper; + int char_idx, char_len, mbclen; + + pstr->wcs = re_malloc (wchar_t, pstr->len + 1); + mbs_upper = re_malloc (unsigned char, pstr->len + 1); + if (pstr->wcs == NULL || mbs_upper == NULL) + { + pstr->wcs = NULL; + return REG_ESPACE; + } + + memset (&state, '\0', sizeof (mbstate_t)); + char_len = pstr->len; + for (char_idx = 0 ; char_idx < char_len ; char_idx += mbclen) + { + int byte_idx, remain_len = char_len - char_idx; + prev_st = state; + mbclen = mbrtowc (&wc, pstr->mbs + char_idx, remain_len, &state); + if (mbclen == 1) + { + pstr->wcs[char_idx] = wc; + if (islower (pstr->mbs[char_idx])) + mbs_upper[char_idx] = toupper (pstr->mbs[char_idx]); + else + mbs_upper[char_idx] = pstr->mbs[char_idx]; + } + else if (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0) + /* We treat these cases as a singlebyte character. */ + { + mbclen = 1; + pstr->wcs[char_idx] = (wchar_t) pstr->mbs[char_idx]; + mbs_upper[char_idx] = pstr->mbs[char_idx]; + state = prev_st; + } + else /* mbclen > 1 */ + { + pstr->wcs[char_idx] = wc; + if (iswlower (wc)) + wcrtomb (mbs_upper + char_idx, towupper (wc), &prev_st); + else + memcpy (mbs_upper + char_idx, pstr->mbs + char_idx, mbclen); + for (byte_idx = 1 ; byte_idx < mbclen ; byte_idx++) + pstr->wcs[char_idx + byte_idx] = WEOF; + } + } + pstr->mbs = mbs_upper; + pstr->mbs_alloc = 1; + return REG_NOERROR; +} +#endif /* RE_ENABLE_I18N */ + +static reg_errcode_t +build_upper_buffer (pstr) + re_string_t *pstr; +{ + unsigned char *mbs_upper; + int char_idx, char_len; + + mbs_upper = re_malloc (unsigned char, pstr->len + 1); + if (mbs_upper == NULL) + return REG_ESPACE; + + char_len = pstr->len; + for (char_idx = 0 ; char_idx < char_len ; char_idx ++) + { + if (islower (pstr->mbs[char_idx])) + mbs_upper[char_idx] = toupper (pstr->mbs[char_idx]); + else + mbs_upper[char_idx] = pstr->mbs[char_idx]; + } + pstr->mbs = mbs_upper; + pstr->mbs_alloc = 1; + return REG_NOERROR; +} + +/* Apply TRANS to the buffer in PSTR. We assume that wide char buffer + is already constructed if MB_CUR_MAX > 1. */ + +static reg_errcode_t +re_string_translate_buffer (pstr, trans) + re_string_t *pstr; + RE_TRANSLATE_TYPE trans; +{ + int buf_idx; + unsigned char *transed_buf, *transed_case_buf; +#ifdef DEBUG + assert (trans != NULL); +#endif + if (pstr->mbs_alloc) + { + transed_buf = (unsigned char *) pstr->mbs; + transed_case_buf = re_malloc (unsigned char, pstr->len + 1); + if (transed_case_buf == NULL) + return REG_ESPACE; + pstr->mbs_case_alloc = 1; + } + else + { + transed_buf = re_malloc (unsigned char, pstr->len + 1); + if (transed_buf == NULL) + return REG_ESPACE; + transed_case_buf = NULL; + pstr->mbs_alloc = 1; + } + for (buf_idx = 0 ; buf_idx < pstr->len ; buf_idx++) + { +#ifdef RE_ENABLE_I18N + if (MB_CUR_MAX > 1 && !re_string_is_single_byte_char (pstr, buf_idx)) + transed_buf[buf_idx] = pstr->mbs[buf_idx]; + else +#endif + transed_buf[buf_idx] = trans[pstr->mbs[buf_idx]]; + if (transed_case_buf) + { +#ifdef RE_ENABLE_I18N + if (MB_CUR_MAX > 1 && !re_string_is_single_byte_char (pstr, buf_idx)) + transed_case_buf[buf_idx] = pstr->mbs_case[buf_idx]; + else +#endif + transed_case_buf[buf_idx] = trans[pstr->mbs_case[buf_idx]]; + } + } + if (pstr->mbs_case_alloc == 1) + { + pstr->mbs = transed_buf; + pstr->mbs_case = transed_case_buf; + } + else + { + pstr->mbs = transed_buf; + pstr->mbs_case = transed_buf; + } + return REG_NOERROR; +} + +static void +re_string_destruct (pstr) + re_string_t *pstr; +{ +#ifdef RE_ENABLE_I18N + re_free (pstr->wcs); +#endif /* RE_ENABLE_I18N */ + if (pstr->mbs_alloc) + re_free ((void *) pstr->mbs); + if (pstr->mbs_case_alloc) + re_free ((void *) pstr->mbs_case); +} + +/* Return the context at IDX in INPUT. */ +static unsigned int +re_string_context_at (input, idx, eflags, newline_anchor) + const re_string_t *input; + int idx, eflags, newline_anchor; +{ + int c; + if (idx < 0 || idx == input->len) + { + unsigned int context = 0; + if (idx < 0) + context = CONTEXT_BEGBUF; + else if (idx == input->len) + context = CONTEXT_ENDBUF; + + if ((idx < 0 && !(eflags & REG_NOTBOL)) + || (idx == input->len && !(eflags & REG_NOTEOL))) + return CONTEXT_NEWLINE | context; + else + return context; + } + c = re_string_byte_at (input, idx); + if (IS_WORD_CHAR (c)) + return CONTEXT_WORD; + return (newline_anchor && IS_NEWLINE (c)) ? CONTEXT_NEWLINE : 0; +} + +/* Functions for set operation. */ + +static reg_errcode_t +re_node_set_alloc (set, size) + re_node_set *set; + int size; +{ + set->alloc = size; + set->nelem = 0; + set->elems = re_malloc (int, size); + if (set->elems == NULL) + return REG_ESPACE; + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_init_1 (set, elem) + re_node_set *set; + int elem; +{ + set->alloc = 1; + set->nelem = 1; + set->elems = re_malloc (int, 1); + if (set->elems == NULL) + return REG_ESPACE; + set->elems[0] = elem; + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_init_2 (set, elem1, elem2) + re_node_set *set; + int elem1, elem2; +{ + set->alloc = 2; + set->elems = re_malloc (int, 2); + if (set->elems == NULL) + 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 +re_node_set_init_copy (dest, src) + 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 (int, dest->alloc); + if (dest->elems == NULL) + return REG_ESPACE; + memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); + } + else + re_node_set_init_empty (dest); + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_intersect (dest, src1, src2) + re_node_set *dest; + const re_node_set *src1, *src2; +{ + int i1, i2, id; + if (src1->nelem > 0 && src2->nelem > 0) + { + if (src1->nelem + src2->nelem > dest->alloc) + { + int *new_array; + if (dest->alloc == 0) + new_array = re_malloc (int, src1->nelem + src2->nelem); + else + new_array = re_realloc (dest->elems, int, + src1->nelem + src2->nelem); + dest->alloc = src1->nelem + src2->nelem; + if (new_array == NULL) + return REG_ESPACE; + dest->elems = new_array; + } + } + else + { + dest->nelem = 0; + return REG_NOERROR; + } + + for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) + { + if (src1->elems[i1] > src2->elems[i2]) + { + ++i2; + continue; + } + if (src1->elems[i1] == src2->elems[i2]) + dest->elems[id++] = src2->elems[i2++]; + ++i1; + } + dest->nelem = id; + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_add_intersect (dest, src1, src2) + re_node_set *dest; + const re_node_set *src1, *src2; +{ + int i1, i2, id; + if (src1->nelem > 0 && src2->nelem > 0) + { + if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) + { + int *new_array; + if (dest->alloc == 0) + new_array = re_malloc (int, src1->nelem + src2->nelem); + else + new_array = re_realloc (dest->elems, int, + src1->nelem + src2->nelem + dest->nelem); + dest->alloc = src1->nelem + src2->nelem + dest->nelem; + if (new_array == NULL) + return REG_ESPACE; + dest->elems = new_array; + } + } + else + return REG_NOERROR; + + for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) + { + if (src1->elems[i1] > src2->elems[i2]) + { + ++i2; + continue; + } + if (src1->elems[i1] == src2->elems[i2]) + { + while (id < dest->nelem && dest->elems[id] < src2->elems[i2]) + ++id; + if (id < dest->nelem && dest->elems[id] == src2->elems[i2]) + ++id; + else + { + memmove (dest->elems + id + 1, dest->elems + id, + sizeof (int) * (dest->nelem - id)); + dest->elems[id++] = src2->elems[i2++]; + ++dest->nelem; + } + } + ++i1; + } + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_init_union (dest, src1, src2) + re_node_set *dest; + const re_node_set *src1, *src2; +{ + int i1, i2, id; + if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) + { + dest->alloc = src1->nelem + src2->nelem; + dest->elems = re_malloc (int, dest->alloc); + if (dest->elems == NULL) + 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 (int)); + id += src1->nelem - i1; + } + else if (i2 < src2->nelem) + { + memcpy (dest->elems + id, src2->elems + i2, + (src2->nelem - i2) * sizeof (int)); + id += src2->nelem - i2; + } + dest->nelem = id; + return REG_NOERROR; +} + +static reg_errcode_t +re_node_set_merge (dest, src) + re_node_set *dest; + const re_node_set *src; +{ + int si, di; + if (src == NULL || src->nelem == 0) + return REG_NOERROR; + else if (dest == NULL) + { + dest = re_malloc (re_node_set, 1); + return re_node_set_init_copy (dest, src); + } + if (dest->alloc < src->nelem + dest->nelem) + { + dest->alloc = 2 * (src->nelem + dest->alloc); + dest->elems = re_realloc (dest->elems, int, dest->alloc); + } + + for (si = 0, di = 0 ; si < src->nelem && di < dest->nelem ;) + { + int cp_from, ncp, mid, right, src_elem = src->elems[si]; + /* Binary search the spot we will add the new element. */ + right = dest->nelem; + while (di < right) + { + mid = (di + right) / 2; + if (dest->elems[mid] < src_elem) + di = mid + 1; + else + right = mid; + } + if (di >= dest->nelem) + break; + + if (dest->elems[di] == src_elem) + { + /* Skip since, DEST already has the element. */ + ++di; + ++si; + continue; + } + + /* Skip the src elements which are less than dest->elems[di]. */ + cp_from = si; + while (si < src->nelem && src->elems[si] < dest->elems[di]) + ++si; + /* Copy these src elements. */ + ncp = si - cp_from; + memmove (dest->elems + di + ncp, dest->elems + di, + sizeof (int) * (dest->nelem - di)); + memcpy (dest->elems + di, src->elems + cp_from, + sizeof (int) * ncp); + /* Update counters. */ + di += ncp; + dest->nelem += ncp; + } + + /* Copy remaining src elements. */ + if (si < src->nelem) + { + memcpy (dest->elems + di, src->elems + si, + sizeof (int) * (src->nelem - si)); + dest->nelem += src->nelem - si; + } + return REG_NOERROR; +} + +/* Insert the new element ELEM to the re_node_set* SET. + return 0 if SET already has ELEM, + return -1 if an error is occured, return 1 otherwise. */ + +static int +re_node_set_insert (set, elem) + re_node_set *set; + int elem; +{ + int idx, right, mid; + /* In case of the set is empty. */ + if (set->elems == NULL || set->alloc == 0) + { + if (re_node_set_init_1 (set, elem) == REG_NOERROR) + return 1; + else + return -1; + } + + /* Binary search the spot we will add the new element. */ + idx = 0; + right = set->nelem; + while (idx < right) + { + mid = (idx + right) / 2; + if (set->elems[mid] < elem) + idx = mid + 1; + else + right = mid; + } + + /* Realloc if we need. */ + if (set->alloc < set->nelem + 1) + { + int *new_array; + set->alloc = set->alloc * 2; + new_array = re_malloc (int, set->alloc); + if (new_array == NULL) + return -1; + /* Copy the elements they are followed by the new element. */ + if (idx > 0) + memcpy (new_array, set->elems, sizeof (int) * (idx)); + /* Copy the elements which follows the new element. */ + if (set->nelem - idx > 0) + memcpy (new_array + idx + 1, set->elems + idx, + sizeof (int) * (set->nelem - idx)); + set->elems = new_array; + } + else + { + /* Move the elements which follows the new element. */ + if (set->nelem - idx > 0) + memmove (set->elems + idx + 1, set->elems + idx, + sizeof (int) * (set->nelem - idx)); + } + /* Insert the new element. */ + set->elems[idx] = elem; + ++set->nelem; + return 1; +} + +/* Compare two node sets SET1 and SET2. + return 1 if SET1 and SET2 are equivalent, retrun 0 otherwise. */ + +static int +re_node_set_compare (set1, set2) + const re_node_set *set1, *set2; +{ + int i; + if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) + return 0; + for (i = 0 ; i < set1->nelem ; i++) + if (set1->elems[i] != set2->elems[i]) + return 0; + return 1; +} + +/* Return 1 if SET contains the element ELEM, return 0 otherwise. */ + +static int +re_node_set_contains (set, elem) + const re_node_set *set; + int elem; +{ + int idx, right, mid; + if (set->nelem <= 0) + 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; +} + +static void +re_node_set_remove_at (set, idx) + re_node_set *set; + int idx; +{ + if (idx < 0 || idx >= set->nelem) + return; + if (idx < set->nelem - 1) + memmove (set->elems + idx, set->elems + idx + 1, + sizeof (int) * (set->nelem - idx - 1)); + --set->nelem; +} + + +/* Add the token TOKEN to dfa->nodes, and return the index of the token. + Or return -1, if an error will be occured. */ + +static int +re_dfa_add_node (dfa, token, mode) + re_dfa_t *dfa; + re_token_t token; + int mode; +{ + if (dfa->nodes_len >= dfa->nodes_alloc) + { + re_token_t *new_array; + dfa->nodes_alloc *= 2; + new_array = re_realloc (dfa->nodes, re_token_t, dfa->nodes_alloc); + if (new_array == NULL) + return -1; + else + dfa->nodes = new_array; + if (mode) + { + int *new_firsts, *new_nexts; + re_node_set *new_edests, *new_eclosures, *new_inveclosures; + + new_firsts = re_realloc (dfa->firsts, int, dfa->nodes_alloc); + new_nexts = re_realloc (dfa->nexts, int, dfa->nodes_alloc); + new_edests = re_realloc (dfa->edests, re_node_set, dfa->nodes_alloc); + new_eclosures = re_realloc (dfa->eclosures, re_node_set, + dfa->nodes_alloc); + new_inveclosures = re_realloc (dfa->inveclosures, re_node_set, + dfa->nodes_alloc); + if (new_firsts == NULL || new_nexts == NULL || new_edests == NULL + || new_eclosures == NULL || new_inveclosures == NULL) + return -1; + dfa->firsts = new_firsts; + dfa->nexts = new_nexts; + dfa->edests = new_edests; + dfa->eclosures = new_eclosures; + dfa->inveclosures = new_inveclosures; + } + } + dfa->nodes[dfa->nodes_len] = token; + dfa->nodes[dfa->nodes_len].duplicated = 0; + return dfa->nodes_len++; +} + +static unsigned int inline +calc_state_hash (nodes, context) + const re_node_set *nodes; + unsigned int context; +{ + unsigned int hash = nodes->nelem + context; + int 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. */ + +static re_dfastate_t * +re_acquire_state (dfa, nodes) + re_dfa_t *dfa; + const re_node_set *nodes; +{ + unsigned int hash; + struct re_state_table_entry *spot; + int i; + if (nodes->nelem == 0) + return NULL; + hash = calc_state_hash (nodes, 0); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + if (spot->alloc == 0) + { + /* Currently there are only one state in this spot. */ + if (spot->entry.state != NULL && hash == spot->entry.state->hash + && re_node_set_compare (&spot->entry.state->nodes, nodes)) + return spot->entry.state; + } + else + for (i = 0 ; i < spot->num ; i++) + { + re_dfastate_t *state = spot->entry.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. */ + return create_ci_newstate (dfa, nodes, hash); +} + +/* 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. */ + +static re_dfastate_t * +re_acquire_state_context (dfa, nodes, context) + re_dfa_t *dfa; + const re_node_set *nodes; + unsigned int context; +{ + unsigned int hash; + struct re_state_table_entry *spot; + int i; + if (nodes->nelem == 0) + return NULL; + hash = calc_state_hash (nodes, context); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + if (spot->alloc == 0) + { + /* Currently there are only one state in this spot. */ + if (spot->entry.state != NULL && hash == spot->entry.state->hash + && re_node_set_compare (&spot->entry.state->nodes, nodes) + && spot->entry.state->context == context) + return spot->entry.state; + } + else + for (i = 0 ; i < spot->num ; i++) + { + re_dfastate_t *state = spot->entry.array[i]; + if (hash != state->hash) + continue; + if (re_node_set_compare (state->entrance_nodes, nodes) + && state->context == context) + return state; + } + /* There are no appropriate state in `dfa', create the new one. */ + return create_cd_newstate (dfa, nodes, context, hash); +} + +static re_dfastate_t * +create_newstate_common (dfa, nodes, hash) + re_dfa_t *dfa; + const re_node_set *nodes; + unsigned int hash; +{ + re_dfastate_t *newstate; + newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + re_node_set_init_copy (&newstate->nodes, nodes); + newstate->trtable = NULL; + newstate->trtable_search = NULL; + newstate->hash = hash; + return newstate; +} + +static void +register_state (dfa, newstate, hash) + re_dfa_t *dfa; + re_dfastate_t *newstate; + unsigned int hash; +{ + struct re_state_table_entry *spot; + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + if (spot->alloc <= spot->num) + { + re_dfastate_t **new_array; + + /* XXX Is spot->entry.array == NULL if spot->alloc == 0? If yes + the if can go away and only realloc is needed. */ + if (spot->alloc == 0) + { + spot->alloc = 4; + new_array = re_malloc (re_dfastate_t *, spot->alloc); + if (new_array == NULL) + /* XXX return value */ + return; + new_array[0] = spot->entry.state; + } + else + { + spot->alloc = 2 * spot->num; + new_array = re_realloc (spot->entry.array, re_dfastate_t *, + spot->alloc); + } + spot->entry.array = new_array; + } + spot->entry.array[spot->num++] = newstate; +} + +static re_dfastate_t * +create_ci_newstate (dfa, nodes, hash) + re_dfa_t *dfa; + const re_node_set *nodes; + unsigned int hash; +{ + int i; + re_dfastate_t *newstate; + newstate = create_newstate_common (dfa, nodes, hash); + 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) + continue; + + /* If the state has the halt node, the state is a halt state. */ + else if (type == END_OF_RE) + newstate->halt = 1; + else if (type == COMPLEX_BRACKET + || (type == OP_PERIOD && MB_CUR_MAX > 1)) + newstate->accept_mb = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + else if (type == ANCHOR || OP_CONTEXT_NODE) + { + newstate->has_constraint = 1; + if (type == OP_CONTEXT_NODE + && dfa->nodes[node->opr.ctx_info->entity].type == END_OF_RE) + newstate->halt = 1; + } + } + + register_state (dfa, newstate, hash); + return newstate; +} + +static re_dfastate_t * +create_cd_newstate (dfa, nodes, context, hash) + re_dfa_t *dfa; + const re_node_set *nodes; + unsigned int context, hash; +{ + int i, nctx_nodes = 0; + re_dfastate_t *newstate; + + newstate = create_newstate_common (dfa, nodes, hash); + newstate->context = context; + newstate->entrance_nodes = &newstate->nodes; + + for (i = 0 ; i < nodes->nelem ; i++) + { + unsigned int constraint = 0; + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + if (type == CHARACTER) + continue; + + /* If the state has the halt node, the state is a halt state. */ + else if (type == END_OF_RE) + newstate->halt = 1; + else if (type == COMPLEX_BRACKET + || (type == OP_PERIOD && MB_CUR_MAX > 1)) + newstate->accept_mb = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + else if (type == ANCHOR) + constraint = node->opr.ctx_type; + else if (type == OP_CONTEXT_NODE) + { + re_token_type_t ctype = dfa->nodes[node->opr.ctx_info->entity].type; + constraint = node->constraint; + if (ctype == END_OF_RE) + newstate->halt = 1; + else if (ctype == OP_BACK_REF) + newstate->has_backref = 1; + else if (ctype == COMPLEX_BRACKET + || (type == OP_PERIOD && MB_CUR_MAX > 1)) + newstate->accept_mb = 1; + } + + if (constraint) + { + if (newstate->entrance_nodes == &newstate->nodes) + { + newstate->entrance_nodes = re_malloc (re_node_set, 1); + if (newstate->entrance_nodes == NULL) + /* XXX Return which value? */ + return NULL; + re_node_set_init_copy (newstate->entrance_nodes, nodes); + 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; + } + } + } + register_state (dfa, newstate, hash); + return newstate; +} |