18 |
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
19 |
|
|
20 |
static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, |
static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, |
21 |
int length, reg_syntax_t syntax); |
Idx length, reg_syntax_t syntax); |
22 |
static void re_compile_fastmap_iter (regex_t *bufp, |
static void re_compile_fastmap_iter (regex_t *bufp, |
23 |
const re_dfastate_t *init_state, |
const re_dfastate_t *init_state, |
24 |
char *fastmap); |
char *fastmap); |
25 |
static reg_errcode_t init_dfa (re_dfa_t *dfa, int pat_len); |
static reg_errcode_t init_dfa (re_dfa_t *dfa, Idx pat_len); |
|
static void init_word_char (re_dfa_t *dfa); |
|
26 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
27 |
static void free_charset (re_charset_t *cset); |
static void free_charset (re_charset_t *cset); |
28 |
#endif /* RE_ENABLE_I18N */ |
#endif /* RE_ENABLE_I18N */ |
32 |
static void optimize_utf8 (re_dfa_t *dfa); |
static void optimize_utf8 (re_dfa_t *dfa); |
33 |
#endif |
#endif |
34 |
static reg_errcode_t analyze (regex_t *preg); |
static reg_errcode_t analyze (regex_t *preg); |
|
static reg_errcode_t create_initial_state (re_dfa_t *dfa); |
|
35 |
static reg_errcode_t preorder (bin_tree_t *root, |
static reg_errcode_t preorder (bin_tree_t *root, |
36 |
reg_errcode_t (fn (void *, bin_tree_t *)), |
reg_errcode_t (fn (void *, bin_tree_t *)), |
37 |
void *extra); |
void *extra); |
45 |
static reg_errcode_t calc_first (void *extra, bin_tree_t *node); |
static reg_errcode_t calc_first (void *extra, bin_tree_t *node); |
46 |
static reg_errcode_t calc_next (void *extra, bin_tree_t *node); |
static reg_errcode_t calc_next (void *extra, bin_tree_t *node); |
47 |
static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); |
static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); |
48 |
static reg_errcode_t duplicate_node_closure (re_dfa_t *dfa, int top_org_node, |
static Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint); |
49 |
int top_clone_node, int root_node, |
static Idx search_duplicated_node (const re_dfa_t *dfa, Idx org_node, |
|
unsigned int constraint); |
|
|
static reg_errcode_t duplicate_node (int *new_idx, re_dfa_t *dfa, int org_idx, |
|
|
unsigned int constraint); |
|
|
static int search_duplicated_node (re_dfa_t *dfa, int org_node, |
|
50 |
unsigned int constraint); |
unsigned int constraint); |
51 |
static reg_errcode_t calc_eclosure (re_dfa_t *dfa); |
static reg_errcode_t calc_eclosure (re_dfa_t *dfa); |
52 |
static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, |
static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, |
53 |
int node, int root); |
Idx node, bool root); |
54 |
static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); |
static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); |
55 |
static int fetch_number (re_string_t *input, re_token_t *token, |
static Idx fetch_number (re_string_t *input, re_token_t *token, |
|
reg_syntax_t syntax); |
|
|
static void fetch_token (re_token_t *result, re_string_t *input, |
|
56 |
reg_syntax_t syntax); |
reg_syntax_t syntax); |
57 |
static int peek_token (re_token_t *token, re_string_t *input, |
static int peek_token (re_token_t *token, re_string_t *input, |
58 |
reg_syntax_t syntax); |
reg_syntax_t syntax); |
|
static int peek_token_bracket (re_token_t *token, re_string_t *input, |
|
|
reg_syntax_t syntax); |
|
59 |
static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, |
static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, |
60 |
reg_syntax_t syntax, reg_errcode_t *err); |
reg_syntax_t syntax, reg_errcode_t *err); |
61 |
static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, |
static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, |
62 |
re_token_t *token, reg_syntax_t syntax, |
re_token_t *token, reg_syntax_t syntax, |
63 |
int nest, reg_errcode_t *err); |
Idx nest, reg_errcode_t *err); |
64 |
static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, |
static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, |
65 |
re_token_t *token, reg_syntax_t syntax, |
re_token_t *token, reg_syntax_t syntax, |
66 |
int nest, reg_errcode_t *err); |
Idx nest, reg_errcode_t *err); |
67 |
static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, |
static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, |
68 |
re_token_t *token, reg_syntax_t syntax, |
re_token_t *token, reg_syntax_t syntax, |
69 |
int nest, reg_errcode_t *err); |
Idx nest, reg_errcode_t *err); |
70 |
static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, |
static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, |
71 |
re_token_t *token, reg_syntax_t syntax, |
re_token_t *token, reg_syntax_t syntax, |
72 |
int nest, reg_errcode_t *err); |
Idx nest, reg_errcode_t *err); |
73 |
static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, |
static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, |
74 |
re_dfa_t *dfa, re_token_t *token, |
re_dfa_t *dfa, re_token_t *token, |
75 |
reg_syntax_t syntax, reg_errcode_t *err); |
reg_syntax_t syntax, reg_errcode_t *err); |
81 |
re_token_t *token, int token_len, |
re_token_t *token, int token_len, |
82 |
re_dfa_t *dfa, |
re_dfa_t *dfa, |
83 |
reg_syntax_t syntax, |
reg_syntax_t syntax, |
84 |
int accept_hyphen); |
bool accept_hyphen); |
85 |
static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, |
static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, |
86 |
re_string_t *regexp, |
re_string_t *regexp, |
87 |
re_token_t *token); |
re_token_t *token); |
|
#ifndef _LIBC |
|
|
# ifdef RE_ENABLE_I18N |
|
|
static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, |
|
|
re_charset_t *mbcset, int *range_alloc, |
|
|
bracket_elem_t *start_elem, |
|
|
bracket_elem_t *end_elem); |
|
|
static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, |
|
|
re_charset_t *mbcset, |
|
|
int *coll_sym_alloc, |
|
|
const unsigned char *name); |
|
|
# else /* not RE_ENABLE_I18N */ |
|
|
static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, |
|
|
bracket_elem_t *start_elem, |
|
|
bracket_elem_t *end_elem); |
|
|
static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, |
|
|
const unsigned char *name); |
|
|
# endif /* not RE_ENABLE_I18N */ |
|
|
#endif /* not _LIBC */ |
|
88 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
89 |
static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, |
static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, |
90 |
re_charset_t *mbcset, |
re_charset_t *mbcset, |
91 |
int *equiv_class_alloc, |
Idx *equiv_class_alloc, |
92 |
const unsigned char *name); |
const unsigned char *name); |
93 |
static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans, |
static reg_errcode_t build_charclass (unsigned REG_TRANSLATE_TYPE trans, |
94 |
re_bitset_ptr_t sbcset, |
re_bitset_ptr_t sbcset, |
95 |
re_charset_t *mbcset, |
re_charset_t *mbcset, |
96 |
int *char_class_alloc, |
Idx *char_class_alloc, |
97 |
const unsigned char *class_name, |
const unsigned char *class_name, |
98 |
reg_syntax_t syntax); |
reg_syntax_t syntax); |
99 |
#else /* not RE_ENABLE_I18N */ |
#else /* not RE_ENABLE_I18N */ |
100 |
static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, |
static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, |
101 |
const unsigned char *name); |
const unsigned char *name); |
102 |
static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans, |
static reg_errcode_t build_charclass (unsigned REG_TRANSLATE_TYPE trans, |
103 |
re_bitset_ptr_t sbcset, |
re_bitset_ptr_t sbcset, |
104 |
const unsigned char *class_name, |
const unsigned char *class_name, |
105 |
reg_syntax_t syntax); |
reg_syntax_t syntax); |
106 |
#endif /* not RE_ENABLE_I18N */ |
#endif /* not RE_ENABLE_I18N */ |
107 |
static bin_tree_t *build_charclass_op (re_dfa_t *dfa, |
static bin_tree_t *build_charclass_op (re_dfa_t *dfa, |
108 |
unsigned RE_TRANSLATE_TYPE trans, |
unsigned REG_TRANSLATE_TYPE trans, |
109 |
const unsigned char *class_name, |
const unsigned char *class_name, |
110 |
const unsigned char *extra, |
const unsigned char *extra, |
111 |
int non_match, reg_errcode_t *err); |
bool non_match, reg_errcode_t *err); |
112 |
static bin_tree_t *create_tree (re_dfa_t *dfa, |
static bin_tree_t *create_tree (re_dfa_t *dfa, |
113 |
bin_tree_t *left, bin_tree_t *right, |
bin_tree_t *left, bin_tree_t *right, |
114 |
re_token_type_t type); |
re_token_type_t type); |
206 |
compiles PATTERN (of length LENGTH) and puts the result in BUFP. |
compiles PATTERN (of length LENGTH) and puts the result in BUFP. |
207 |
Returns 0 if the pattern was valid, otherwise an error string. |
Returns 0 if the pattern was valid, otherwise an error string. |
208 |
|
|
209 |
Assumes the `allocated' (and perhaps `buffer') and `translate' fields |
Assumes the `re_allocated' (and perhaps `re_buffer') and `translate' fields |
210 |
are set in BUFP on entry. */ |
are set in BUFP on entry. */ |
211 |
|
|
212 |
const char * |
const char * |
213 |
re_compile_pattern (pattern, length, bufp) |
re_compile_pattern (const char *pattern, size_t length, |
214 |
const char *pattern; |
struct re_pattern_buffer *bufp) |
|
size_t length; |
|
|
struct re_pattern_buffer *bufp; |
|
215 |
{ |
{ |
216 |
reg_errcode_t ret; |
reg_errcode_t ret; |
217 |
|
|
218 |
/* And GNU code determines whether or not to get register information |
/* And GNU code determines whether or not to get register information |
219 |
by passing null for the REGS argument to re_match, etc., not by |
by passing null for the REGS argument to re_match, etc., not by |
220 |
setting no_sub, unless RE_NO_SUB is set. */ |
setting re_no_sub, unless REG_NO_SUB is set. */ |
221 |
bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); |
bufp->re_no_sub = !!(re_syntax_options & REG_NO_SUB); |
222 |
|
|
223 |
/* Match anchors at newline. */ |
/* Match anchors at newline. */ |
224 |
bufp->newline_anchor = 1; |
bufp->re_newline_anchor = 1; |
225 |
|
|
226 |
ret = re_compile_internal (bufp, pattern, length, re_syntax_options); |
ret = re_compile_internal (bufp, pattern, length, re_syntax_options); |
227 |
|
|
249 |
defined in regex.h. We return the old syntax. */ |
defined in regex.h. We return the old syntax. */ |
250 |
|
|
251 |
reg_syntax_t |
reg_syntax_t |
252 |
re_set_syntax (syntax) |
re_set_syntax (reg_syntax_t syntax) |
|
reg_syntax_t syntax; |
|
253 |
{ |
{ |
254 |
reg_syntax_t ret = re_syntax_options; |
reg_syntax_t ret = re_syntax_options; |
255 |
|
|
261 |
#endif |
#endif |
262 |
|
|
263 |
int |
int |
264 |
re_compile_fastmap (bufp) |
re_compile_fastmap (struct re_pattern_buffer *bufp) |
|
struct re_pattern_buffer *bufp; |
|
265 |
{ |
{ |
266 |
re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; |
re_dfa_t *dfa = (re_dfa_t *) bufp->re_buffer; |
267 |
char *fastmap = bufp->fastmap; |
char *fastmap = bufp->re_fastmap; |
268 |
|
|
269 |
memset (fastmap, '\0', sizeof (char) * SBC_MAX); |
memset (fastmap, '\0', sizeof (char) * SBC_MAX); |
270 |
re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); |
re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); |
274 |
re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); |
re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); |
275 |
if (dfa->init_state != dfa->init_state_begbuf) |
if (dfa->init_state != dfa->init_state_begbuf) |
276 |
re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); |
re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); |
277 |
bufp->fastmap_accurate = 1; |
bufp->re_fastmap_accurate = 1; |
278 |
return 0; |
return 0; |
279 |
} |
} |
280 |
#ifdef _LIBC |
#ifdef _LIBC |
283 |
|
|
284 |
static inline void |
static inline void |
285 |
__attribute ((always_inline)) |
__attribute ((always_inline)) |
286 |
re_set_fastmap (char *fastmap, int icase, int ch) |
re_set_fastmap (char *fastmap, bool icase, int ch) |
287 |
{ |
{ |
288 |
fastmap[ch] = 1; |
fastmap[ch] = 1; |
289 |
if (icase) |
if (icase) |
294 |
Compile fastmap for the initial_state INIT_STATE. */ |
Compile fastmap for the initial_state INIT_STATE. */ |
295 |
|
|
296 |
static void |
static void |
297 |
re_compile_fastmap_iter (bufp, init_state, fastmap) |
re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
298 |
regex_t *bufp; |
char *fastmap) |
299 |
const re_dfastate_t *init_state; |
{ |
300 |
char *fastmap; |
re_dfa_t *dfa = (re_dfa_t *) bufp->re_buffer; |
301 |
{ |
Idx node_cnt; |
302 |
re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; |
bool icase = (dfa->mb_cur_max == 1 && (bufp->re_syntax & REG_IGNORE_CASE)); |
|
int node_cnt; |
|
|
int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); |
|
303 |
for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) |
for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) |
304 |
{ |
{ |
305 |
int node = init_state->nodes.elems[node_cnt]; |
Idx node = init_state->nodes.elems[node_cnt]; |
306 |
re_token_type_t type = dfa->nodes[node].type; |
re_token_type_t type = dfa->nodes[node].type; |
307 |
|
|
308 |
if (type == CHARACTER) |
if (type == CHARACTER) |
309 |
{ |
{ |
310 |
re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); |
re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); |
311 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
312 |
if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) |
if ((bufp->re_syntax & REG_IGNORE_CASE) && dfa->mb_cur_max > 1) |
313 |
{ |
{ |
314 |
unsigned char *buf = alloca (dfa->mb_cur_max), *p; |
unsigned char buf[MB_LEN_MAX]; |
315 |
|
unsigned char *p; |
316 |
wchar_t wc; |
wchar_t wc; |
317 |
mbstate_t state; |
mbstate_t state; |
318 |
|
|
327 |
&state) == p - buf |
&state) == p - buf |
328 |
&& (__wcrtomb ((char *) buf, towlower (wc), &state) |
&& (__wcrtomb ((char *) buf, towlower (wc), &state) |
329 |
!= (size_t) -1)) |
!= (size_t) -1)) |
330 |
re_set_fastmap (fastmap, 0, buf[0]); |
re_set_fastmap (fastmap, false, buf[0]); |
331 |
} |
} |
332 |
#endif |
#endif |
333 |
} |
} |
336 |
int i, j, ch; |
int i, j, ch; |
337 |
for (i = 0, ch = 0; i < BITSET_UINTS; ++i) |
for (i = 0, ch = 0; i < BITSET_UINTS; ++i) |
338 |
for (j = 0; j < UINT_BITS; ++j, ++ch) |
for (j = 0; j < UINT_BITS; ++j, ++ch) |
339 |
if (dfa->nodes[node].opr.sbcset[i] & (1 << j)) |
if (dfa->nodes[node].opr.sbcset[i] & (1u << j)) |
340 |
re_set_fastmap (fastmap, icase, ch); |
re_set_fastmap (fastmap, icase, ch); |
341 |
} |
} |
342 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
343 |
else if (type == COMPLEX_BRACKET) |
else if (type == COMPLEX_BRACKET) |
344 |
{ |
{ |
345 |
int i; |
Idx i; |
346 |
re_charset_t *cset = dfa->nodes[node].opr.mbcset; |
re_charset_t *cset = dfa->nodes[node].opr.mbcset; |
347 |
if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes |
if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes |
348 |
|| cset->nranges || cset->nchar_classes) |
|| cset->nranges || cset->nchar_classes) |
378 |
memset (&state, '\0', sizeof (state)); |
memset (&state, '\0', sizeof (state)); |
379 |
if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) |
if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) |
380 |
re_set_fastmap (fastmap, icase, *(unsigned char *) buf); |
re_set_fastmap (fastmap, icase, *(unsigned char *) buf); |
381 |
if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) |
if ((bufp->re_syntax & REG_IGNORE_CASE) && dfa->mb_cur_max > 1) |
382 |
{ |
{ |
383 |
if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) |
if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) |
384 |
!= (size_t) -1) |
!= (size_t) -1) |
385 |
re_set_fastmap (fastmap, 0, *(unsigned char *) buf); |
re_set_fastmap (fastmap, false, *(unsigned char *) buf); |
386 |
} |
} |
387 |
} |
} |
388 |
} |
} |
395 |
{ |
{ |
396 |
memset (fastmap, '\1', sizeof (char) * SBC_MAX); |
memset (fastmap, '\1', sizeof (char) * SBC_MAX); |
397 |
if (type == END_OF_RE) |
if (type == END_OF_RE) |
398 |
bufp->can_be_null = 1; |
bufp->re_can_be_null = 1; |
399 |
return; |
return; |
400 |
} |
} |
401 |
} |
} |
407 |
PREG is a regex_t *. We do not expect any fields to be initialized, |
PREG is a regex_t *. We do not expect any fields to be initialized, |
408 |
since POSIX says we shouldn't. Thus, we set |
since POSIX says we shouldn't. Thus, we set |
409 |
|
|
410 |
`buffer' to the compiled pattern; |
`re_buffer' to the compiled pattern; |
411 |
`used' to the length of the compiled pattern; |
`re_used' to the length of the compiled pattern; |
412 |
`syntax' to RE_SYNTAX_POSIX_EXTENDED if the |
`re_syntax' to REG_SYNTAX_POSIX_EXTENDED if the |
413 |
REG_EXTENDED bit in CFLAGS is set; otherwise, to |
REG_EXTENDED bit in CFLAGS is set; otherwise, to |
414 |
RE_SYNTAX_POSIX_BASIC; |
REG_SYNTAX_POSIX_BASIC; |
415 |
`newline_anchor' to REG_NEWLINE being set in CFLAGS; |
`re_newline_anchor' to REG_NEWLINE being set in CFLAGS; |
416 |
`fastmap' to an allocated space for the fastmap; |
`re_fastmap' to an allocated space for the fastmap; |
417 |
`fastmap_accurate' to zero; |
`re_fastmap_accurate' to zero; |
418 |
`re_nsub' to the number of subexpressions in PATTERN. |
`re_nsub' to the number of subexpressions in PATTERN. |
419 |
|
|
420 |
PATTERN is the address of the pattern string. |
PATTERN is the address of the pattern string. |
438 |
the return codes and their meanings.) */ |
the return codes and their meanings.) */ |
439 |
|
|
440 |
int |
int |
441 |
regcomp (preg, pattern, cflags) |
regcomp (regex_t *__restrict preg, const char *__restrict pattern, int cflags) |
|
regex_t *__restrict preg; |
|
|
const char *__restrict pattern; |
|
|
int cflags; |
|
442 |
{ |
{ |
443 |
reg_errcode_t ret; |
reg_errcode_t ret; |
444 |
reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED |
reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? REG_SYNTAX_POSIX_EXTENDED |
445 |
: RE_SYNTAX_POSIX_BASIC); |
: REG_SYNTAX_POSIX_BASIC); |
446 |
|
|
447 |
preg->buffer = NULL; |
preg->re_buffer = NULL; |
448 |
preg->allocated = 0; |
preg->re_allocated = 0; |
449 |
preg->used = 0; |
preg->re_used = 0; |
450 |
|
|
451 |
/* Try to allocate space for the fastmap. */ |
/* Try to allocate space for the fastmap. */ |
452 |
preg->fastmap = re_malloc (char, SBC_MAX); |
preg->re_fastmap = re_malloc (char, SBC_MAX); |
453 |
if (BE (preg->fastmap == NULL, 0)) |
if (BE (preg->re_fastmap == NULL, 0)) |
454 |
return REG_ESPACE; |
return REG_ESPACE; |
455 |
|
|
456 |
syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; |
syntax |= (cflags & REG_ICASE) ? REG_IGNORE_CASE : 0; |
457 |
|
|
458 |
/* If REG_NEWLINE is set, newlines are treated differently. */ |
/* If REG_NEWLINE is set, newlines are treated differently. */ |
459 |
if (cflags & REG_NEWLINE) |
if (cflags & REG_NEWLINE) |
460 |
{ /* REG_NEWLINE implies neither . nor [^...] match newline. */ |
{ /* REG_NEWLINE implies neither . nor [^...] match newline. */ |
461 |
syntax &= ~RE_DOT_NEWLINE; |
syntax &= ~REG_DOT_NEWLINE; |
462 |
syntax |= RE_HAT_LISTS_NOT_NEWLINE; |
syntax |= REG_HAT_LISTS_NOT_NEWLINE; |
463 |
/* It also changes the matching behavior. */ |
/* It also changes the matching behavior. */ |
464 |
preg->newline_anchor = 1; |
preg->re_newline_anchor = 1; |
465 |
} |
} |
466 |
else |
else |
467 |
preg->newline_anchor = 0; |
preg->re_newline_anchor = 0; |
468 |
preg->no_sub = !!(cflags & REG_NOSUB); |
preg->re_no_sub = !!(cflags & REG_NOSUB); |
469 |
preg->translate = NULL; |
preg->re_translate = NULL; |
470 |
|
|
471 |
ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); |
ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); |
472 |
|
|
475 |
if (ret == REG_ERPAREN) |
if (ret == REG_ERPAREN) |
476 |
ret = REG_EPAREN; |
ret = REG_EPAREN; |
477 |
|
|
478 |
/* We have already checked preg->fastmap != NULL. */ |
/* We have already checked preg->re_fastmap != NULL. */ |
479 |
if (BE (ret == REG_NOERROR, 1)) |
if (BE (ret == REG_NOERROR, 1)) |
480 |
/* Compute the fastmap now, since regexec cannot modify the pattern |
/* Compute the fastmap now, since regexec cannot modify the pattern |
481 |
buffer. This function never fails in this implementation. */ |
buffer. This function never fails in this implementation. */ |
483 |
else |
else |
484 |
{ |
{ |
485 |
/* Some error occurred while compiling the expression. */ |
/* Some error occurred while compiling the expression. */ |
486 |
re_free (preg->fastmap); |
re_free (preg->re_fastmap); |
487 |
preg->fastmap = NULL; |
preg->re_fastmap = NULL; |
488 |
} |
} |
489 |
|
|
490 |
return (int) ret; |
return (int) ret; |
497 |
from either regcomp or regexec. We don't use PREG here. */ |
from either regcomp or regexec. We don't use PREG here. */ |
498 |
|
|
499 |
size_t |
size_t |
500 |
regerror (errcode, preg, errbuf, errbuf_size) |
regerror (int errcode, const regex_t *__restrict preg, |
501 |
int errcode; |
char *__restrict errbuf, size_t errbuf_size) |
|
const regex_t *preg; |
|
|
char *errbuf; |
|
|
size_t errbuf_size; |
|
502 |
{ |
{ |
503 |
const char *msg; |
const char *msg; |
504 |
size_t msg_size; |
size_t msg_size; |
558 |
static void |
static void |
559 |
free_dfa_content (re_dfa_t *dfa) |
free_dfa_content (re_dfa_t *dfa) |
560 |
{ |
{ |
561 |
int i, j; |
Idx i, j; |
562 |
|
|
563 |
if (dfa->nodes) |
if (dfa->nodes) |
564 |
for (i = 0; i < dfa->nodes_len; ++i) |
for (i = 0; i < dfa->nodes_len; ++i) |
606 |
/* Free dynamically allocated space used by PREG. */ |
/* Free dynamically allocated space used by PREG. */ |
607 |
|
|
608 |
void |
void |
609 |
regfree (preg) |
regfree (regex_t *preg) |
|
regex_t *preg; |
|
610 |
{ |
{ |
611 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
612 |
if (BE (dfa != NULL, 1)) |
if (BE (dfa != NULL, 1)) |
613 |
free_dfa_content (dfa); |
free_dfa_content (dfa); |
614 |
preg->buffer = NULL; |
preg->re_buffer = NULL; |
615 |
preg->allocated = 0; |
preg->re_allocated = 0; |
616 |
|
|
617 |
re_free (preg->fastmap); |
re_free (preg->re_fastmap); |
618 |
preg->fastmap = NULL; |
preg->re_fastmap = NULL; |
619 |
|
|
620 |
re_free (preg->translate); |
re_free (preg->re_translate); |
621 |
preg->translate = NULL; |
preg->re_translate = NULL; |
622 |
} |
} |
623 |
#ifdef _LIBC |
#ifdef _LIBC |
624 |
weak_alias (__regfree, regfree) |
weak_alias (__regfree, regfree) |
639 |
regcomp/regexec above without link errors. */ |
regcomp/regexec above without link errors. */ |
640 |
weak_function |
weak_function |
641 |
# endif |
# endif |
642 |
re_comp (s) |
re_comp (const char *s) |
|
const char *s; |
|
643 |
{ |
{ |
644 |
reg_errcode_t ret; |
reg_errcode_t ret; |
645 |
char *fastmap; |
char *fastmap; |
646 |
|
|
647 |
if (!s) |
if (!s) |
648 |
{ |
{ |
649 |
if (!re_comp_buf.buffer) |
if (!re_comp_buf.re_buffer) |
650 |
return gettext ("No previous regular expression"); |
return gettext ("No previous regular expression"); |
651 |
return 0; |
return 0; |
652 |
} |
} |
653 |
|
|
654 |
if (re_comp_buf.buffer) |
if (re_comp_buf.re_buffer) |
655 |
{ |
{ |
656 |
fastmap = re_comp_buf.fastmap; |
fastmap = re_comp_buf.re_fastmap; |
657 |
re_comp_buf.fastmap = NULL; |
re_comp_buf.re_fastmap = NULL; |
658 |
__regfree (&re_comp_buf); |
__regfree (&re_comp_buf); |
659 |
memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); |
memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); |
660 |
re_comp_buf.fastmap = fastmap; |
re_comp_buf.re_fastmap = fastmap; |
661 |
} |
} |
662 |
|
|
663 |
if (re_comp_buf.fastmap == NULL) |
if (re_comp_buf.re_fastmap == NULL) |
664 |
{ |
{ |
665 |
re_comp_buf.fastmap = (char *) malloc (SBC_MAX); |
re_comp_buf.re_fastmap = (char *) malloc (SBC_MAX); |
666 |
if (re_comp_buf.fastmap == NULL) |
if (re_comp_buf.re_fastmap == NULL) |
667 |
return (char *) gettext (__re_error_msgid |
return (char *) gettext (__re_error_msgid |
668 |
+ __re_error_msgid_idx[(int) REG_ESPACE]); |
+ __re_error_msgid_idx[(int) REG_ESPACE]); |
669 |
} |
} |
672 |
don't need to initialize the pattern buffer fields which affect it. */ |
don't need to initialize the pattern buffer fields which affect it. */ |
673 |
|
|
674 |
/* Match anchors at newlines. */ |
/* Match anchors at newlines. */ |
675 |
re_comp_buf.newline_anchor = 1; |
re_comp_buf.re_newline_anchor = 1; |
676 |
|
|
677 |
ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); |
ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); |
678 |
|
|
697 |
SYNTAX indicate regular expression's syntax. */ |
SYNTAX indicate regular expression's syntax. */ |
698 |
|
|
699 |
static reg_errcode_t |
static reg_errcode_t |
700 |
re_compile_internal (preg, pattern, length, syntax) |
re_compile_internal (regex_t *preg, const char *pattern, Idx length, |
701 |
regex_t *preg; |
reg_syntax_t syntax) |
|
const char * pattern; |
|
|
int length; |
|
|
reg_syntax_t syntax; |
|
702 |
{ |
{ |
703 |
reg_errcode_t err = REG_NOERROR; |
reg_errcode_t err = REG_NOERROR; |
704 |
re_dfa_t *dfa; |
re_dfa_t *dfa; |
705 |
re_string_t regexp; |
re_string_t regexp; |
706 |
|
|
707 |
/* Initialize the pattern buffer. */ |
/* Initialize the pattern buffer. */ |
708 |
preg->fastmap_accurate = 0; |
preg->re_fastmap_accurate = 0; |
709 |
preg->syntax = syntax; |
preg->re_syntax = syntax; |
710 |
preg->not_bol = preg->not_eol = 0; |
preg->re_not_bol = preg->re_not_eol = 0; |
711 |
preg->used = 0; |
preg->re_used = 0; |
712 |
preg->re_nsub = 0; |
preg->re_nsub = 0; |
713 |
preg->can_be_null = 0; |
preg->re_can_be_null = 0; |
714 |
preg->regs_allocated = REGS_UNALLOCATED; |
preg->re_regs_allocated = REG_UNALLOCATED; |
715 |
|
|
716 |
/* Initialize the dfa. */ |
/* Initialize the dfa. */ |
717 |
dfa = (re_dfa_t *) preg->buffer; |
dfa = (re_dfa_t *) preg->re_buffer; |
718 |
if (BE (preg->allocated < sizeof (re_dfa_t), 0)) |
if (BE (preg->re_allocated < sizeof (re_dfa_t), 0)) |
719 |
{ |
{ |
720 |
/* If zero allocated, but buffer is non-null, try to realloc |
/* If zero allocated, but buffer is non-null, try to realloc |
721 |
enough space. This loses if buffer's address is bogus, but |
enough space. This loses if buffer's address is bogus, but |
722 |
that is the user's responsibility. If ->buffer is NULL this |
that is the user's responsibility. If buffer is null this |
723 |
is a simple allocation. */ |
is a simple allocation. */ |
724 |
dfa = re_realloc (preg->buffer, re_dfa_t, 1); |
dfa = re_realloc (preg->re_buffer, re_dfa_t, 1); |
725 |
if (dfa == NULL) |
if (dfa == NULL) |
726 |
return REG_ESPACE; |
return REG_ESPACE; |
727 |
preg->allocated = sizeof (re_dfa_t); |
preg->re_allocated = sizeof (re_dfa_t); |
728 |
preg->buffer = (unsigned char *) dfa; |
preg->re_buffer = (unsigned char *) dfa; |
729 |
} |
} |
730 |
preg->used = sizeof (re_dfa_t); |
preg->re_used = sizeof (re_dfa_t); |
731 |
|
|
732 |
__libc_lock_init (dfa->lock); |
__libc_lock_init (dfa->lock); |
733 |
|
|
735 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
736 |
{ |
{ |
737 |
free_dfa_content (dfa); |
free_dfa_content (dfa); |
738 |
preg->buffer = NULL; |
preg->re_buffer = NULL; |
739 |
preg->allocated = 0; |
preg->re_allocated = 0; |
740 |
return err; |
return err; |
741 |
} |
} |
742 |
#ifdef DEBUG |
#ifdef DEBUG |
744 |
strncpy (dfa->re_str, pattern, length + 1); |
strncpy (dfa->re_str, pattern, length + 1); |
745 |
#endif |
#endif |
746 |
|
|
747 |
err = re_string_construct (®exp, pattern, length, preg->translate, |
err = re_string_construct (®exp, pattern, length, preg->re_translate, |
748 |
syntax & RE_ICASE, dfa); |
syntax & REG_IGNORE_CASE, dfa); |
749 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
750 |
{ |
{ |
751 |
re_compile_internal_free_return: |
re_compile_internal_free_return: |
752 |
free_workarea_compile (preg); |
free_workarea_compile (preg); |
753 |
re_string_destruct (®exp); |
re_string_destruct (®exp); |
754 |
free_dfa_content (dfa); |
free_dfa_content (dfa); |
755 |
preg->buffer = NULL; |
preg->re_buffer = NULL; |
756 |
preg->allocated = 0; |
preg->re_allocated = 0; |
757 |
return err; |
return err; |
758 |
} |
} |
759 |
|
|
770 |
|
|
771 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
772 |
/* If possible, do searching in single byte encoding to speed things up. */ |
/* If possible, do searching in single byte encoding to speed things up. */ |
773 |
if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) |
if (dfa->is_utf8 && !(syntax & REG_IGNORE_CASE) && preg->re_translate == NULL) |
774 |
optimize_utf8 (dfa); |
optimize_utf8 (dfa); |
775 |
#endif |
#endif |
776 |
|
|
784 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
785 |
{ |
{ |
786 |
free_dfa_content (dfa); |
free_dfa_content (dfa); |
787 |
preg->buffer = NULL; |
preg->re_buffer = NULL; |
788 |
preg->allocated = 0; |
preg->re_allocated = 0; |
789 |
} |
} |
790 |
|
|
791 |
return err; |
return err; |
795 |
as the initial length of some arrays. */ |
as the initial length of some arrays. */ |
796 |
|
|
797 |
static reg_errcode_t |
static reg_errcode_t |
798 |
init_dfa (dfa, pat_len) |
init_dfa (re_dfa_t *dfa, Idx pat_len) |
|
re_dfa_t *dfa; |
|
|
int pat_len; |
|
799 |
{ |
{ |
800 |
int table_size; |
__re_size_t table_size; |
801 |
#ifndef _LIBC |
#ifndef _LIBC |
802 |
char *codeset_name; |
char *codeset_name; |
803 |
#endif |
#endif |
808 |
dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; |
dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; |
809 |
|
|
810 |
dfa->nodes_alloc = pat_len + 1; |
dfa->nodes_alloc = pat_len + 1; |
811 |
dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); |
dfa->nodes = re_xmalloc (re_token_t, dfa->nodes_alloc); |
|
|
|
|
dfa->states_alloc = pat_len + 1; |
|
812 |
|
|
813 |
/* table_size = 2 ^ ceil(log pat_len) */ |
/* table_size = 2 ^ ceil(log pat_len) */ |
814 |
for (table_size = 1; table_size > 0; table_size <<= 1) |
for (table_size = 1; table_size <= pat_len; table_size <<= 1) |
815 |
if (table_size > pat_len) |
if (0 < (Idx) -1 && table_size == 0) |
816 |
break; |
return REG_ESPACE; |
817 |
|
|
818 |
dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); |
dfa->state_table = re_calloc (struct re_state_table_entry, table_size); |
819 |
dfa->state_hash_mask = table_size - 1; |
dfa->state_hash_mask = table_size - 1; |
820 |
|
|
821 |
dfa->mb_cur_max = MB_CUR_MAX; |
dfa->mb_cur_max = MB_CUR_MAX; |
858 |
{ |
{ |
859 |
int i, j, ch; |
int i, j, ch; |
860 |
|
|
861 |
dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset), 1); |
dfa->sb_char = re_calloc (unsigned int, BITSET_UINTS); |
862 |
if (BE (dfa->sb_char == NULL, 0)) |
if (BE (dfa->sb_char == NULL, 0)) |
863 |
return REG_ESPACE; |
return REG_ESPACE; |
864 |
|
|
871 |
{ |
{ |
872 |
wint_t wch = __btowc (ch); |
wint_t wch = __btowc (ch); |
873 |
if (wch != WEOF) |
if (wch != WEOF) |
874 |
dfa->sb_char[i] |= 1 << j; |
dfa->sb_char[i] |= 1u << j; |
875 |
# ifndef _LIBC |
# ifndef _LIBC |
876 |
if (isascii (ch) && wch != ch) |
if (isascii (ch) && wch != ch) |
877 |
dfa->map_notascii = 1; |
dfa->map_notascii = 1; |
891 |
character used by some operators like "\<", "\>", etc. */ |
character used by some operators like "\<", "\>", etc. */ |
892 |
|
|
893 |
static void |
static void |
894 |
init_word_char (dfa) |
init_word_char (re_dfa_t *dfa) |
|
re_dfa_t *dfa; |
|
895 |
{ |
{ |
896 |
int i, j, ch; |
int i, j, ch; |
897 |
dfa->word_ops_used = 1; |
dfa->word_ops_used = 1; |
898 |
for (i = 0, ch = 0; i < BITSET_UINTS; ++i) |
for (i = 0, ch = 0; i < BITSET_UINTS; ++i) |
899 |
for (j = 0; j < UINT_BITS; ++j, ++ch) |
for (j = 0; j < UINT_BITS; ++j, ++ch) |
900 |
if (isalnum (ch) || ch == '_') |
if (isalnum (ch) || ch == '_') |
901 |
dfa->word_char[i] |= 1 << j; |
dfa->word_char[i] |= 1u << j; |
902 |
} |
} |
903 |
|
|
904 |
/* Free the work area which are only used while compiling. */ |
/* Free the work area which are only used while compiling. */ |
905 |
|
|
906 |
static void |
static void |
907 |
free_workarea_compile (preg) |
free_workarea_compile (regex_t *preg) |
|
regex_t *preg; |
|
908 |
{ |
{ |
909 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
910 |
bin_tree_storage_t *storage, *next; |
bin_tree_storage_t *storage, *next; |
911 |
for (storage = dfa->str_tree_storage; storage; storage = next) |
for (storage = dfa->str_tree_storage; storage; storage = next) |
912 |
{ |
{ |
923 |
/* Create initial states for all contexts. */ |
/* Create initial states for all contexts. */ |
924 |
|
|
925 |
static reg_errcode_t |
static reg_errcode_t |
926 |
create_initial_state (dfa) |
create_initial_state (re_dfa_t *dfa) |
|
re_dfa_t *dfa; |
|
927 |
{ |
{ |
928 |
int first, i; |
Idx first, i; |
929 |
reg_errcode_t err; |
reg_errcode_t err; |
930 |
re_node_set init_nodes; |
re_node_set init_nodes; |
931 |
|
|
944 |
if (dfa->nbackref > 0) |
if (dfa->nbackref > 0) |
945 |
for (i = 0; i < init_nodes.nelem; ++i) |
for (i = 0; i < init_nodes.nelem; ++i) |
946 |
{ |
{ |
947 |
int node_idx = init_nodes.elems[i]; |
Idx node_idx = init_nodes.elems[i]; |
948 |
re_token_type_t type = dfa->nodes[node_idx].type; |
re_token_type_t type = dfa->nodes[node_idx].type; |
949 |
|
|
950 |
int clexp_idx; |
Idx clexp_idx; |
951 |
if (type != OP_BACK_REF) |
if (type != OP_BACK_REF) |
952 |
continue; |
continue; |
953 |
for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) |
for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) |
963 |
|
|
964 |
if (type == OP_BACK_REF) |
if (type == OP_BACK_REF) |
965 |
{ |
{ |
966 |
int dest_idx = dfa->edests[node_idx].elems[0]; |
Idx dest_idx = dfa->edests[node_idx].elems[0]; |
967 |
if (!re_node_set_contains (&init_nodes, dest_idx)) |
if (!re_node_set_contains (&init_nodes, dest_idx)) |
968 |
{ |
{ |
969 |
re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); |
re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); |
1005 |
DFA nodes where needed. */ |
DFA nodes where needed. */ |
1006 |
|
|
1007 |
static void |
static void |
1008 |
optimize_utf8 (dfa) |
optimize_utf8 (re_dfa_t *dfa) |
|
re_dfa_t *dfa; |
|
1009 |
{ |
{ |
1010 |
int node, i, mb_chars = 0, has_period = 0; |
Idx node; |
1011 |
|
int i; |
1012 |
|
bool mb_chars = false; |
1013 |
|
bool has_period = false; |
1014 |
|
|
1015 |
for (node = 0; node < dfa->nodes_len; ++node) |
for (node = 0; node < dfa->nodes_len; ++node) |
1016 |
switch (dfa->nodes[node].type) |
switch (dfa->nodes[node].type) |
1017 |
{ |
{ |
1018 |
case CHARACTER: |
case CHARACTER: |
1019 |
if (dfa->nodes[node].opr.c >= 0x80) |
if (dfa->nodes[node].opr.c >= 0x80) |
1020 |
mb_chars = 1; |
mb_chars = true; |
1021 |
break; |
break; |
1022 |
case ANCHOR: |
case ANCHOR: |
1023 |
switch (dfa->nodes[node].opr.idx) |
switch (dfa->nodes[node].opr.idx) |
1033 |
} |
} |
1034 |
break; |
break; |
1035 |
case OP_PERIOD: |
case OP_PERIOD: |
1036 |
has_period = 1; |
has_period = true; |
1037 |
break; |
break; |
1038 |
case OP_BACK_REF: |
case OP_BACK_REF: |
1039 |
case OP_ALT: |
case OP_ALT: |
1075 |
"eclosure", and "inveclosure". */ |
"eclosure", and "inveclosure". */ |
1076 |
|
|
1077 |
static reg_errcode_t |
static reg_errcode_t |
1078 |
analyze (preg) |
analyze (regex_t *preg) |
|
regex_t *preg; |
|
1079 |
{ |
{ |
1080 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
1081 |
reg_errcode_t ret; |
reg_errcode_t ret; |
1082 |
|
|
1083 |
/* Allocate arrays. */ |
/* Allocate arrays. */ |
1084 |
dfa->nexts = re_malloc (int, dfa->nodes_alloc); |
dfa->nexts = re_malloc (Idx, dfa->nodes_alloc); |
1085 |
dfa->org_indices = re_malloc (int, dfa->nodes_alloc); |
dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc); |
1086 |
dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); |
dfa->edests = re_xmalloc (re_node_set, dfa->nodes_alloc); |
1087 |
dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); |
dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); |
1088 |
if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL |
if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL |
1089 |
|| dfa->eclosures == NULL, 0)) |
|| dfa->eclosures == NULL, 0)) |
1090 |
return REG_ESPACE; |
return REG_ESPACE; |
1091 |
|
|
1092 |
dfa->subexp_map = re_malloc (int, preg->re_nsub); |
dfa->subexp_map = re_xmalloc (Idx, preg->re_nsub); |
1093 |
if (dfa->subexp_map != NULL) |
if (dfa->subexp_map != NULL) |
1094 |
{ |
{ |
1095 |
int i; |
Idx i; |
1096 |
for (i = 0; i < preg->re_nsub; i++) |
for (i = 0; i < preg->re_nsub; i++) |
1097 |
dfa->subexp_map[i] = i; |
dfa->subexp_map[i] = i; |
1098 |
preorder (dfa->str_tree, optimize_subexps, dfa); |
preorder (dfa->str_tree, optimize_subexps, dfa); |
1122 |
|
|
1123 |
/* We only need this during the prune_impossible_nodes pass in regexec.c; |
/* We only need this during the prune_impossible_nodes pass in regexec.c; |
1124 |
skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ |
skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ |
1125 |
if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) |
if ((!preg->re_no_sub && preg->re_nsub > 0 && dfa->has_plural_match) |
1126 |
|| dfa->nbackref) |
|| dfa->nbackref) |
1127 |
{ |
{ |
1128 |
dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); |
dfa->inveclosures = re_xmalloc (re_node_set, dfa->nodes_len); |
1129 |
if (BE (dfa->inveclosures == NULL, 0)) |
if (BE (dfa->inveclosures == NULL, 0)) |
1130 |
return REG_ESPACE; |
return REG_ESPACE; |
1131 |
ret = calc_inveclosure (dfa); |
ret = calc_inveclosure (dfa); |
1138 |
implement parse tree visits. Instead, we use parent pointers and |
implement parse tree visits. Instead, we use parent pointers and |
1139 |
some hairy code in these two functions. */ |
some hairy code in these two functions. */ |
1140 |
static reg_errcode_t |
static reg_errcode_t |
1141 |
postorder (root, fn, extra) |
postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), |
1142 |
bin_tree_t *root; |
void *extra) |
|
reg_errcode_t (fn (void *, bin_tree_t *)); |
|
|
void *extra; |
|
1143 |
{ |
{ |
1144 |
bin_tree_t *node, *prev; |
bin_tree_t *node, *prev; |
1145 |
|
|
1170 |
} |
} |
1171 |
|
|
1172 |
static reg_errcode_t |
static reg_errcode_t |
1173 |
preorder (root, fn, extra) |
preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), |
1174 |
bin_tree_t *root; |
void *extra) |
|
reg_errcode_t (fn (void *, bin_tree_t *)); |
|
|
void *extra; |
|
1175 |
{ |
{ |
1176 |
bin_tree_t *node; |
bin_tree_t *node; |
1177 |
|
|
1203 |
re_search_internal to map the inner one's opr.idx to this one's. Adjust |
re_search_internal to map the inner one's opr.idx to this one's. Adjust |
1204 |
backreferences as well. Requires a preorder visit. */ |
backreferences as well. Requires a preorder visit. */ |
1205 |
static reg_errcode_t |
static reg_errcode_t |
1206 |
optimize_subexps (extra, node) |
optimize_subexps (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
1207 |
{ |
{ |
1208 |
re_dfa_t *dfa = (re_dfa_t *) extra; |
re_dfa_t *dfa = (re_dfa_t *) extra; |
1209 |
|
|
1217 |
else if (node->token.type == SUBEXP |
else if (node->token.type == SUBEXP |
1218 |
&& node->left && node->left->token.type == SUBEXP) |
&& node->left && node->left->token.type == SUBEXP) |
1219 |
{ |
{ |
1220 |
int other_idx = node->left->token.opr.idx; |
Idx other_idx = node->left->token.opr.idx; |
1221 |
|
|
1222 |
node->left = node->left->left; |
node->left = node->left->left; |
1223 |
if (node->left) |
if (node->left) |
1224 |
node->left->parent = node; |
node->left->parent = node; |
1225 |
|
|
1226 |
dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; |
dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; |
1227 |
if (other_idx < 8 * sizeof (dfa->used_bkref_map)) |
if (other_idx < CHAR_BIT * sizeof dfa->used_bkref_map) |
1228 |
dfa->used_bkref_map &= ~(1 << other_idx); |
dfa->used_bkref_map &= ~(1u << other_idx); |
1229 |
} |
} |
1230 |
|
|
1231 |
return REG_NOERROR; |
return REG_NOERROR; |
1234 |
/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation |
/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation |
1235 |
of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ |
of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ |
1236 |
static reg_errcode_t |
static reg_errcode_t |
1237 |
lower_subexps (extra, node) |
lower_subexps (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
1238 |
{ |
{ |
1239 |
regex_t *preg = (regex_t *) extra; |
regex_t *preg = (regex_t *) extra; |
1240 |
reg_errcode_t err = REG_NOERROR; |
reg_errcode_t err = REG_NOERROR; |
1256 |
} |
} |
1257 |
|
|
1258 |
static bin_tree_t * |
static bin_tree_t * |
1259 |
lower_subexp (err, preg, node) |
lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) |
|
reg_errcode_t *err; |
|
|
regex_t *preg; |
|
|
bin_tree_t *node; |
|
1260 |
{ |
{ |
1261 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
1262 |
bin_tree_t *body = node->left; |
bin_tree_t *body = node->left; |
1263 |
bin_tree_t *op, *cls, *tree1, *tree; |
bin_tree_t *op, *cls, *tree1, *tree; |
1264 |
|
|
1265 |
if (preg->no_sub |
if (preg->re_no_sub |
1266 |
/* We do not optimize empty subexpressions, because otherwise we may |
/* We do not optimize empty subexpressions, because otherwise we may |
1267 |
have bad CONCAT nodes with NULL children. This is obviously not |
have bad CONCAT nodes with NULL children. This is obviously not |
1268 |
very common, so we do not lose much. An example that triggers |
very common, so we do not lose much. An example that triggers |
1269 |
this case is the sed "script" /\(\)/x. */ |
this case is the sed "script" /\(\)/x. */ |
1270 |
&& node->left != NULL |
&& node->left != NULL |
1271 |
&& (node->token.opr.idx >= 8 * sizeof (dfa->used_bkref_map) |
&& (node->token.opr.idx >= CHAR_BIT * sizeof dfa->used_bkref_map |
1272 |
|| !(dfa->used_bkref_map & (1 << node->token.opr.idx)))) |
|| !(dfa->used_bkref_map & (1u << node->token.opr.idx)))) |
1273 |
return node->left; |
return node->left; |
1274 |
|
|
1275 |
/* Convert the SUBEXP node to the concatenation of an |
/* Convert the SUBEXP node to the concatenation of an |
1292 |
/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton |
/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton |
1293 |
nodes. Requires a postorder visit. */ |
nodes. Requires a postorder visit. */ |
1294 |
static reg_errcode_t |
static reg_errcode_t |
1295 |
calc_first (extra, node) |
calc_first (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
1296 |
{ |
{ |
1297 |
re_dfa_t *dfa = (re_dfa_t *) extra; |
re_dfa_t *dfa = (re_dfa_t *) extra; |
1298 |
if (node->token.type == CONCAT) |
if (node->token.type == CONCAT) |
1304 |
{ |
{ |
1305 |
node->first = node; |
node->first = node; |
1306 |
node->node_idx = re_dfa_add_node (dfa, node->token); |
node->node_idx = re_dfa_add_node (dfa, node->token); |
1307 |
if (BE (node->node_idx == -1, 0)) |
if (BE (node->node_idx == REG_MISSING, 0)) |
1308 |
return REG_ESPACE; |
return REG_ESPACE; |
1309 |
} |
} |
1310 |
return REG_NOERROR; |
return REG_NOERROR; |
1312 |
|
|
1313 |
/* Pass 2: compute NEXT on the tree. Preorder visit. */ |
/* Pass 2: compute NEXT on the tree. Preorder visit. */ |
1314 |
static reg_errcode_t |
static reg_errcode_t |
1315 |
calc_next (extra, node) |
calc_next (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
1316 |
{ |
{ |
1317 |
switch (node->token.type) |
switch (node->token.type) |
1318 |
{ |
{ |
1335 |
|
|
1336 |
/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ |
/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ |
1337 |
static reg_errcode_t |
static reg_errcode_t |
1338 |
link_nfa_nodes (extra, node) |
link_nfa_nodes (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
1339 |
{ |
{ |
1340 |
re_dfa_t *dfa = (re_dfa_t *) extra; |
re_dfa_t *dfa = (re_dfa_t *) extra; |
1341 |
int idx = node->node_idx; |
Idx idx = node->node_idx; |
1342 |
reg_errcode_t err = REG_NOERROR; |
reg_errcode_t err = REG_NOERROR; |
1343 |
|
|
1344 |
switch (node->token.type) |
switch (node->token.type) |
1353 |
case OP_DUP_ASTERISK: |
case OP_DUP_ASTERISK: |
1354 |
case OP_ALT: |
case OP_ALT: |
1355 |
{ |
{ |
1356 |
int left, right; |
Idx left, right; |
1357 |
dfa->has_plural_match = 1; |
dfa->has_plural_match = 1; |
1358 |
if (node->left != NULL) |
if (node->left != NULL) |
1359 |
left = node->left->first->node_idx; |
left = node->left->first->node_idx; |
1363 |
right = node->right->first->node_idx; |
right = node->right->first->node_idx; |
1364 |
else |
else |
1365 |
right = node->next->node_idx; |
right = node->next->node_idx; |
1366 |
assert (left > -1); |
assert (REG_VALID_INDEX (left)); |
1367 |
assert (right > -1); |
assert (REG_VALID_INDEX (right)); |
1368 |
err = re_node_set_init_2 (dfa->edests + idx, left, right); |
err = re_node_set_init_2 (dfa->edests + idx, left, right); |
1369 |
} |
} |
1370 |
break; |
break; |
1395 |
to their own constraint. */ |
to their own constraint. */ |
1396 |
|
|
1397 |
static reg_errcode_t |
static reg_errcode_t |
1398 |
duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, |
duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node, |
1399 |
init_constraint) |
Idx top_clone_node, Idx root_node, |
1400 |
re_dfa_t *dfa; |
unsigned int init_constraint) |
|
int top_org_node, top_clone_node, root_node; |
|
|
unsigned int init_constraint; |
|
1401 |
{ |
{ |
1402 |
reg_errcode_t err; |
Idx org_node, clone_node; |
1403 |
int org_node, clone_node, ret; |
bool ok; |
1404 |
unsigned int constraint = init_constraint; |
unsigned int constraint = init_constraint; |
1405 |
for (org_node = top_org_node, clone_node = top_clone_node;;) |
for (org_node = top_org_node, clone_node = top_clone_node;;) |
1406 |
{ |
{ |
1407 |
int org_dest, clone_dest; |
Idx org_dest, clone_dest; |
1408 |
if (dfa->nodes[org_node].type == OP_BACK_REF) |
if (dfa->nodes[org_node].type == OP_BACK_REF) |
1409 |
{ |
{ |
1410 |
/* If the back reference epsilon-transit, its destination must |
/* If the back reference epsilon-transit, its destination must |
1413 |
edests of the back reference. */ |
edests of the back reference. */ |
1414 |
org_dest = dfa->nexts[org_node]; |
org_dest = dfa->nexts[org_node]; |
1415 |
re_node_set_empty (dfa->edests + clone_node); |
re_node_set_empty (dfa->edests + clone_node); |
1416 |
err = duplicate_node (&clone_dest, dfa, org_dest, constraint); |
clone_dest = duplicate_node (dfa, org_dest, constraint); |
1417 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (clone_dest == REG_MISSING, 0)) |
1418 |
return err; |
return REG_ESPACE; |
1419 |
dfa->nexts[clone_node] = dfa->nexts[org_node]; |
dfa->nexts[clone_node] = dfa->nexts[org_node]; |
1420 |
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
1421 |
if (BE (ret < 0, 0)) |
if (BE (! ok, 0)) |
1422 |
return REG_ESPACE; |
return REG_ESPACE; |
1423 |
} |
} |
1424 |
else if (dfa->edests[org_node].nelem == 0) |
else if (dfa->edests[org_node].nelem == 0) |
1443 |
/* ...but if the node is root_node itself, it means the |
/* ...but if the node is root_node itself, it means the |
1444 |
epsilon closure have a loop, then tie it to the |
epsilon closure have a loop, then tie it to the |
1445 |
destination of the root_node. */ |
destination of the root_node. */ |
1446 |
ret = re_node_set_insert (dfa->edests + clone_node, |
ok = re_node_set_insert (dfa->edests + clone_node, |
1447 |
org_dest); |
org_dest); |
1448 |
if (BE (ret < 0, 0)) |
if (BE (! ok, 0)) |
1449 |
return REG_ESPACE; |
return REG_ESPACE; |
1450 |
break; |
break; |
1451 |
} |
} |
1452 |
constraint |= dfa->nodes[org_node].opr.ctx_type; |
constraint |= dfa->nodes[org_node].opr.ctx_type; |
1453 |
} |
} |
1454 |
err = duplicate_node (&clone_dest, dfa, org_dest, constraint); |
clone_dest = duplicate_node (dfa, org_dest, constraint); |
1455 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (clone_dest == REG_MISSING, 0)) |
1456 |
return err; |
return REG_ESPACE; |
1457 |
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
1458 |
if (BE (ret < 0, 0)) |
if (BE (! ok, 0)) |
1459 |
return REG_ESPACE; |
return REG_ESPACE; |
1460 |
} |
} |
1461 |
else /* dfa->edests[org_node].nelem == 2 */ |
else /* dfa->edests[org_node].nelem == 2 */ |
1466 |
re_node_set_empty (dfa->edests + clone_node); |
re_node_set_empty (dfa->edests + clone_node); |
1467 |
/* Search for a duplicated node which satisfies the constraint. */ |
/* Search for a duplicated node which satisfies the constraint. */ |
1468 |
clone_dest = search_duplicated_node (dfa, org_dest, constraint); |
clone_dest = search_duplicated_node (dfa, org_dest, constraint); |
1469 |
if (clone_dest == -1) |
if (clone_dest == REG_MISSING) |
1470 |
{ |
{ |
1471 |
/* There are no such a duplicated node, create a new one. */ |
/* There are no such a duplicated node, create a new one. */ |
1472 |
err = duplicate_node (&clone_dest, dfa, org_dest, constraint); |
reg_errcode_t err; |
1473 |
if (BE (err != REG_NOERROR, 0)) |
clone_dest = duplicate_node (dfa, org_dest, constraint); |
1474 |
return err; |
if (BE (clone_dest == REG_MISSING, 0)) |
1475 |
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
return REG_ESPACE; |
1476 |
if (BE (ret < 0, 0)) |
ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
1477 |
|
if (BE (! ok, 0)) |
1478 |
return REG_ESPACE; |
return REG_ESPACE; |
1479 |
err = duplicate_node_closure (dfa, org_dest, clone_dest, |
err = duplicate_node_closure (dfa, org_dest, clone_dest, |
1480 |
root_node, constraint); |
root_node, constraint); |
1485 |
{ |
{ |
1486 |
/* There are a duplicated node which satisfy the constraint, |
/* There are a duplicated node which satisfy the constraint, |
1487 |
use it to avoid infinite loop. */ |
use it to avoid infinite loop. */ |
1488 |
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
1489 |
if (BE (ret < 0, 0)) |
if (BE (! ok, 0)) |
1490 |
return REG_ESPACE; |
return REG_ESPACE; |
1491 |
} |
} |
1492 |
|
|
1493 |
org_dest = dfa->edests[org_node].elems[1]; |
org_dest = dfa->edests[org_node].elems[1]; |
1494 |
err = duplicate_node (&clone_dest, dfa, org_dest, constraint); |
clone_dest = duplicate_node (dfa, org_dest, constraint); |
1495 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (clone_dest == REG_MISSING, 0)) |
1496 |
return err; |
return REG_ESPACE; |
1497 |
ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); |
1498 |
if (BE (ret < 0, 0)) |
if (BE (! ok, 0)) |
1499 |
return REG_ESPACE; |
return REG_ESPACE; |
1500 |
} |
} |
1501 |
org_node = org_dest; |
org_node = org_dest; |
1507 |
/* Search for a node which is duplicated from the node ORG_NODE, and |
/* Search for a node which is duplicated from the node ORG_NODE, and |
1508 |
satisfies the constraint CONSTRAINT. */ |
satisfies the constraint CONSTRAINT. */ |
1509 |
|
|
1510 |
static int |
static Idx |
1511 |
search_duplicated_node (dfa, org_node, constraint) |
search_duplicated_node (const re_dfa_t *dfa, Idx org_node, |
1512 |
re_dfa_t *dfa; |
unsigned int constraint) |
|
int org_node; |
|
|
unsigned int constraint; |
|
1513 |
{ |
{ |
1514 |
int idx; |
Idx idx; |
1515 |
for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) |
for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) |
1516 |
{ |
{ |
1517 |
if (org_node == dfa->org_indices[idx] |
if (org_node == dfa->org_indices[idx] |
1518 |
&& constraint == dfa->nodes[idx].constraint) |
&& constraint == dfa->nodes[idx].constraint) |
1519 |
return idx; /* Found. */ |
return idx; /* Found. */ |
1520 |
} |
} |
1521 |
return -1; /* Not found. */ |
return REG_MISSING; /* Not found. */ |
1522 |
} |
} |
1523 |
|
|
1524 |
/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. |
/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. |
1525 |
The new index will be stored in NEW_IDX and return REG_NOERROR if succeeded, |
Return the index of the new node, or REG_MISSING if insufficient storage is |
1526 |
otherwise return the error code. */ |
available. */ |
1527 |
|
|
1528 |
static reg_errcode_t |
static Idx |
1529 |
duplicate_node (new_idx, dfa, org_idx, constraint) |
duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint) |
|
re_dfa_t *dfa; |
|
|
int *new_idx, org_idx; |
|
|
unsigned int constraint; |
|
1530 |
{ |
{ |
1531 |
int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); |
Idx dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); |
1532 |
if (BE (dup_idx == -1, 0)) |
if (BE (dup_idx != REG_MISSING, 1)) |
1533 |
return REG_ESPACE; |
{ |
1534 |
dfa->nodes[dup_idx].constraint = constraint; |
dfa->nodes[dup_idx].constraint = constraint; |
1535 |
if (dfa->nodes[org_idx].type == ANCHOR) |
if (dfa->nodes[org_idx].type == ANCHOR) |
1536 |
dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; |
dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; |
1537 |
dfa->nodes[dup_idx].duplicated = 1; |
dfa->nodes[dup_idx].duplicated = 1; |
1538 |
|
|
1539 |
/* Store the index of the original node. */ |
/* Store the index of the original node. */ |
1540 |
dfa->org_indices[dup_idx] = org_idx; |
dfa->org_indices[dup_idx] = org_idx; |
1541 |
*new_idx = dup_idx; |
} |
1542 |
return REG_NOERROR; |
return dup_idx; |
1543 |
} |
} |
1544 |
|
|
1545 |
static reg_errcode_t |
static reg_errcode_t |
1546 |
calc_inveclosure (dfa) |
calc_inveclosure (re_dfa_t *dfa) |
|
re_dfa_t *dfa; |
|
1547 |
{ |
{ |
1548 |
int src, idx, ret; |
Idx src, idx; |
1549 |
|
bool ok; |
1550 |
for (idx = 0; idx < dfa->nodes_len; ++idx) |
for (idx = 0; idx < dfa->nodes_len; ++idx) |
1551 |
re_node_set_init_empty (dfa->inveclosures + idx); |
re_node_set_init_empty (dfa->inveclosures + idx); |
1552 |
|
|
1553 |
for (src = 0; src < dfa->nodes_len; ++src) |
for (src = 0; src < dfa->nodes_len; ++src) |
1554 |
{ |
{ |
1555 |
int *elems = dfa->eclosures[src].elems; |
Idx *elems = dfa->eclosures[src].elems; |
1556 |
for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) |
for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) |
1557 |
{ |
{ |
1558 |
ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); |
ok = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); |
1559 |
if (BE (ret == -1, 0)) |
if (BE (! ok, 0)) |
1560 |
return REG_ESPACE; |
return REG_ESPACE; |
1561 |
} |
} |
1562 |
} |
} |
1567 |
/* Calculate "eclosure" for all the node in DFA. */ |
/* Calculate "eclosure" for all the node in DFA. */ |
1568 |
|
|
1569 |
static reg_errcode_t |
static reg_errcode_t |
1570 |
calc_eclosure (dfa) |
calc_eclosure (re_dfa_t *dfa) |
|
re_dfa_t *dfa; |
|
1571 |
{ |
{ |
1572 |
int node_idx, incomplete; |
Idx node_idx; |
1573 |
|
bool incomplete; |
1574 |
#ifdef DEBUG |
#ifdef DEBUG |
1575 |
assert (dfa->nodes_len > 0); |
assert (dfa->nodes_len > 0); |
1576 |
#endif |
#endif |
1577 |
incomplete = 0; |
incomplete = false; |
1578 |
/* For each nodes, calculate epsilon closure. */ |
/* For each nodes, calculate epsilon closure. */ |
1579 |
for (node_idx = 0; ; ++node_idx) |
for (node_idx = 0; ; ++node_idx) |
1580 |
{ |
{ |
1584 |
{ |
{ |
1585 |
if (!incomplete) |
if (!incomplete) |
1586 |
break; |
break; |
1587 |
incomplete = 0; |
incomplete = false; |
1588 |
node_idx = 0; |
node_idx = 0; |
1589 |
} |
} |
1590 |
|
|
1591 |
#ifdef DEBUG |
#ifdef DEBUG |
1592 |
assert (dfa->eclosures[node_idx].nelem != -1); |
assert (dfa->eclosures[node_idx].nelem != REG_MISSING); |
1593 |
#endif |
#endif |
1594 |
|
|
1595 |
/* If we have already calculated, skip it. */ |
/* If we have already calculated, skip it. */ |
1596 |
if (dfa->eclosures[node_idx].nelem != 0) |
if (dfa->eclosures[node_idx].nelem != 0) |
1597 |
continue; |
continue; |
1598 |
/* Calculate epsilon closure of `node_idx'. */ |
/* Calculate epsilon closure of `node_idx'. */ |
1599 |
err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1); |
err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true); |
1600 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
1601 |
return err; |
return err; |
1602 |
|
|
1603 |
if (dfa->eclosures[node_idx].nelem == 0) |
if (dfa->eclosures[node_idx].nelem == 0) |
1604 |
{ |
{ |
1605 |
incomplete = 1; |
incomplete = true; |
1606 |
re_node_set_free (&eclosure_elem); |
re_node_set_free (&eclosure_elem); |
1607 |
} |
} |
1608 |
} |
} |
1612 |
/* Calculate epsilon closure of NODE. */ |
/* Calculate epsilon closure of NODE. */ |
1613 |
|
|
1614 |
static reg_errcode_t |
static reg_errcode_t |
1615 |
calc_eclosure_iter (new_set, dfa, node, root) |
calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) |
|
re_node_set *new_set; |
|
|
re_dfa_t *dfa; |
|
|
int node, root; |
|
1616 |
{ |
{ |
1617 |
reg_errcode_t err; |
reg_errcode_t err; |
1618 |
unsigned int constraint; |
unsigned int constraint; |
1619 |
int i, incomplete; |
Idx i; |
1620 |
|
bool incomplete; |
1621 |
|
bool ok; |
1622 |
re_node_set eclosure; |
re_node_set eclosure; |
1623 |
incomplete = 0; |
incomplete = false; |
1624 |
err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); |
err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); |
1625 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
1626 |
return err; |
return err; |
1627 |
|
|
1628 |
/* This indicates that we are calculating this node now. |
/* This indicates that we are calculating this node now. |
1629 |
We reference this value to avoid infinite loop. */ |
We reference this value to avoid infinite loop. */ |
1630 |
dfa->eclosures[node].nelem = -1; |
dfa->eclosures[node].nelem = REG_MISSING; |
1631 |
|
|
1632 |
constraint = ((dfa->nodes[node].type == ANCHOR) |
constraint = ((dfa->nodes[node].type == ANCHOR) |
1633 |
? dfa->nodes[node].opr.ctx_type : 0); |
? dfa->nodes[node].opr.ctx_type : 0); |
1637 |
&& dfa->edests[node].nelem |
&& dfa->edests[node].nelem |
1638 |
&& !dfa->nodes[dfa->edests[node].elems[0]].duplicated) |
&& !dfa->nodes[dfa->edests[node].elems[0]].duplicated) |
1639 |
{ |
{ |
1640 |
int org_node, cur_node; |
Idx org_node, cur_node; |
1641 |
org_node = cur_node = node; |
org_node = cur_node = node; |
1642 |
err = duplicate_node_closure (dfa, node, node, node, constraint); |
err = duplicate_node_closure (dfa, node, node, node, constraint); |
1643 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
1649 |
for (i = 0; i < dfa->edests[node].nelem; ++i) |
for (i = 0; i < dfa->edests[node].nelem; ++i) |
1650 |
{ |
{ |
1651 |
re_node_set eclosure_elem; |
re_node_set eclosure_elem; |
1652 |
int edest = dfa->edests[node].elems[i]; |
Idx edest = dfa->edests[node].elems[i]; |
1653 |
/* If calculating the epsilon closure of `edest' is in progress, |
/* If calculating the epsilon closure of `edest' is in progress, |
1654 |
return intermediate result. */ |
return intermediate result. */ |
1655 |
if (dfa->eclosures[edest].nelem == -1) |
if (dfa->eclosures[edest].nelem == REG_MISSING) |
1656 |
{ |
{ |
1657 |
incomplete = 1; |
incomplete = true; |
1658 |
continue; |
continue; |
1659 |
} |
} |
1660 |
/* If we haven't calculated the epsilon closure of `edest' yet, |
/* If we haven't calculated the epsilon closure of `edest' yet, |
1661 |
calculate now. Otherwise use calculated epsilon closure. */ |
calculate now. Otherwise use calculated epsilon closure. */ |
1662 |
if (dfa->eclosures[edest].nelem == 0) |
if (dfa->eclosures[edest].nelem == 0) |
1663 |
{ |
{ |
1664 |
err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0); |
err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false); |
1665 |
if (BE (err != REG_NOERROR, 0)) |
if (BE (err != REG_NOERROR, 0)) |
1666 |
return err; |
return err; |
1667 |
} |
} |
1673 |
the epsilon closure of this node is also incomplete. */ |
the epsilon closure of this node is also incomplete. */ |
1674 |
if (dfa->eclosures[edest].nelem == 0) |
if (dfa->eclosures[edest].nelem == 0) |
1675 |
{ |
{ |
1676 |
incomplete = 1; |
incomplete = true; |
1677 |
re_node_set_free (&eclosure_elem); |
re_node_set_free (&eclosure_elem); |
1678 |
} |
} |
1679 |
} |
} |
1680 |
|
|
1681 |
/* Epsilon closures include itself. */ |
/* Epsilon closures include itself. */ |
1682 |
re_node_set_insert (&eclosure, node); |
ok = re_node_set_insert (&eclosure, node); |
1683 |
|
if (BE (! ok, 0)) |
1684 |
|
return REG_ESPACE; |
1685 |
if (incomplete && !root) |
if (incomplete && !root) |
1686 |
dfa->eclosures[node].nelem = 0; |
dfa->eclosures[node].nelem = 0; |
1687 |
else |
else |
1696 |
We must not use this function inside bracket expressions. */ |
We must not use this function inside bracket expressions. */ |
1697 |
|
|
1698 |
static void |
static void |
1699 |
fetch_token (result, input, syntax) |
fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) |
|
re_token_t *result; |
|
|
re_string_t *input; |
|
|
reg_syntax_t syntax; |
|
1700 |
{ |
{ |
1701 |
re_string_skip_bytes (input, peek_token (result, input, syntax)); |
re_string_skip_bytes (input, peek_token (result, input, syntax)); |
1702 |
} |
} |
1705 |
We must not use this function inside bracket expressions. */ |
We must not use this function inside bracket expressions. */ |
1706 |
|
|
1707 |
static int |
static int |
1708 |
peek_token (token, input, syntax) |
peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
|
re_token_t *token; |
|
|
re_string_t *input; |
|
|
reg_syntax_t syntax; |
|
1709 |
{ |
{ |
1710 |
unsigned char c; |
unsigned char c; |
1711 |
|
|
1755 |
switch (c2) |
switch (c2) |
1756 |
{ |
{ |
1757 |
case '|': |
case '|': |
1758 |
if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) |
if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_NO_BK_VBAR)) |
1759 |
token->type = OP_ALT; |
token->type = OP_ALT; |
1760 |
break; |
break; |
1761 |
case '1': case '2': case '3': case '4': case '5': |
case '1': case '2': case '3': case '4': case '5': |
1762 |
case '6': case '7': case '8': case '9': |
case '6': case '7': case '8': case '9': |
1763 |
if (!(syntax & RE_NO_BK_REFS)) |
if (!(syntax & REG_NO_BK_REFS)) |
1764 |
{ |
{ |
1765 |
token->type = OP_BACK_REF; |
token->type = OP_BACK_REF; |
1766 |
token->opr.idx = c2 - '1'; |
token->opr.idx = c2 - '1'; |
1767 |
} |
} |
1768 |
break; |
break; |
1769 |
case '<': |
case '<': |
1770 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1771 |
{ |
{ |
1772 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1773 |
token->opr.ctx_type = WORD_FIRST; |
token->opr.ctx_type = WORD_FIRST; |
1774 |
} |
} |
1775 |
break; |
break; |
1776 |
case '>': |
case '>': |
1777 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1778 |
{ |
{ |
1779 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1780 |
token->opr.ctx_type = WORD_LAST; |
token->opr.ctx_type = WORD_LAST; |
1781 |
} |
} |
1782 |
break; |
break; |
1783 |
case 'b': |
case 'b': |
1784 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1785 |
{ |
{ |
1786 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1787 |
token->opr.ctx_type = WORD_DELIM; |
token->opr.ctx_type = WORD_DELIM; |
1788 |
} |
} |
1789 |
break; |
break; |
1790 |
case 'B': |
case 'B': |
1791 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1792 |
{ |
{ |
1793 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1794 |
token->opr.ctx_type = NOT_WORD_DELIM; |
token->opr.ctx_type = NOT_WORD_DELIM; |
1795 |
} |
} |
1796 |
break; |
break; |
1797 |
case 'w': |
case 'w': |
1798 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1799 |
token->type = OP_WORD; |
token->type = OP_WORD; |
1800 |
break; |
break; |
1801 |
case 'W': |
case 'W': |
1802 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1803 |
token->type = OP_NOTWORD; |
token->type = OP_NOTWORD; |
1804 |
break; |
break; |
1805 |
case 's': |
case 's': |
1806 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1807 |
token->type = OP_SPACE; |
token->type = OP_SPACE; |
1808 |
break; |
break; |
1809 |
case 'S': |
case 'S': |
1810 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1811 |
token->type = OP_NOTSPACE; |
token->type = OP_NOTSPACE; |
1812 |
break; |
break; |
1813 |
case '`': |
case '`': |
1814 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1815 |
{ |
{ |
1816 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1817 |
token->opr.ctx_type = BUF_FIRST; |
token->opr.ctx_type = BUF_FIRST; |
1818 |
} |
} |
1819 |
break; |
break; |
1820 |
case '\'': |
case '\'': |
1821 |
if (!(syntax & RE_NO_GNU_OPS)) |
if (!(syntax & REG_NO_GNU_OPS)) |
1822 |
{ |
{ |
1823 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1824 |
token->opr.ctx_type = BUF_LAST; |
token->opr.ctx_type = BUF_LAST; |
1825 |
} |
} |
1826 |
break; |
break; |
1827 |
case '(': |
case '(': |
1828 |
if (!(syntax & RE_NO_BK_PARENS)) |
if (!(syntax & REG_NO_BK_PARENS)) |
1829 |
token->type = OP_OPEN_SUBEXP; |
token->type = OP_OPEN_SUBEXP; |
1830 |
break; |
break; |
1831 |
case ')': |
case ')': |
1832 |
if (!(syntax & RE_NO_BK_PARENS)) |
if (!(syntax & REG_NO_BK_PARENS)) |
1833 |
token->type = OP_CLOSE_SUBEXP; |
token->type = OP_CLOSE_SUBEXP; |
1834 |
break; |
break; |
1835 |
case '+': |
case '+': |
1836 |
if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) |
if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_BK_PLUS_QM)) |
1837 |
token->type = OP_DUP_PLUS; |
token->type = OP_DUP_PLUS; |
1838 |
break; |
break; |
1839 |
case '?': |
case '?': |
1840 |
if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) |
if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_BK_PLUS_QM)) |
1841 |
token->type = OP_DUP_QUESTION; |
token->type = OP_DUP_QUESTION; |
1842 |
break; |
break; |
1843 |
case '{': |
case '{': |
1844 |
if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) |
if ((syntax & REG_INTERVALS) && (!(syntax & REG_NO_BK_BRACES))) |
1845 |
token->type = OP_OPEN_DUP_NUM; |
token->type = OP_OPEN_DUP_NUM; |
1846 |
break; |
break; |
1847 |
case '}': |
case '}': |
1848 |
if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) |
if ((syntax & REG_INTERVALS) && (!(syntax & REG_NO_BK_BRACES))) |
1849 |
token->type = OP_CLOSE_DUP_NUM; |
token->type = OP_CLOSE_DUP_NUM; |
1850 |
break; |
break; |
1851 |
default: |
default: |
1868 |
switch (c) |
switch (c) |
1869 |
{ |
{ |
1870 |
case '\n': |
case '\n': |
1871 |
if (syntax & RE_NEWLINE_ALT) |
if (syntax & REG_NEWLINE_ALT) |
1872 |
token->type = OP_ALT; |
token->type = OP_ALT; |
1873 |
break; |
break; |
1874 |
case '|': |
case '|': |
1875 |
if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) |
if (!(syntax & REG_LIMITED_OPS) && (syntax & REG_NO_BK_VBAR)) |
1876 |
token->type = OP_ALT; |
token->type = OP_ALT; |
1877 |
break; |
break; |
1878 |
case '*': |
case '*': |
1879 |
token->type = OP_DUP_ASTERISK; |
token->type = OP_DUP_ASTERISK; |
1880 |
break; |
break; |
1881 |
case '+': |
case '+': |
1882 |
if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) |
if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_BK_PLUS_QM)) |
1883 |
token->type = OP_DUP_PLUS; |
token->type = OP_DUP_PLUS; |
1884 |
break; |
break; |
1885 |
case '?': |
case '?': |
1886 |
if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) |
if (!(syntax & REG_LIMITED_OPS) && !(syntax & REG_BK_PLUS_QM)) |
1887 |
token->type = OP_DUP_QUESTION; |
token->type = OP_DUP_QUESTION; |
1888 |
break; |
break; |
1889 |
case '{': |
case '{': |
1890 |
if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) |
if ((syntax & REG_INTERVALS) && (syntax & REG_NO_BK_BRACES)) |
1891 |
token->type = OP_OPEN_DUP_NUM; |
token->type = OP_OPEN_DUP_NUM; |
1892 |
break; |
break; |
1893 |
case '}': |
case '}': |
1894 |
if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) |
if ((syntax & REG_INTERVALS) && (syntax & REG_NO_BK_BRACES)) |
1895 |
token->type = OP_CLOSE_DUP_NUM; |
token->type = OP_CLOSE_DUP_NUM; |
1896 |
break; |
break; |
1897 |
case '(': |
case '(': |
1898 |
if (syntax & RE_NO_BK_PARENS) |
if (syntax & REG_NO_BK_PARENS) |
1899 |
token->type = OP_OPEN_SUBEXP; |
token->type = OP_OPEN_SUBEXP; |
1900 |
break; |
break; |
1901 |
case ')': |
case ')': |
1902 |
if (syntax & RE_NO_BK_PARENS) |
if (syntax & REG_NO_BK_PARENS) |
1903 |
token->type = OP_CLOSE_SUBEXP; |
token->type = OP_CLOSE_SUBEXP; |
1904 |
break; |
break; |
1905 |
case '[': |
case '[': |
1909 |
token->type = OP_PERIOD; |
token->type = OP_PERIOD; |
1910 |
break; |
break; |
1911 |
case '^': |
case '^': |
1912 |
if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && |
if (!(syntax & (REG_CONTEXT_INDEP_ANCHORS | REG_CARET_ANCHORS_HERE)) && |
1913 |
re_string_cur_idx (input) != 0) |
re_string_cur_idx (input) != 0) |
1914 |
{ |
{ |
1915 |
char prev = re_string_peek_byte (input, -1); |
char prev = re_string_peek_byte (input, -1); |
1916 |
if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') |
if (!(syntax & REG_NEWLINE_ALT) || prev != '\n') |
1917 |
break; |
break; |
1918 |
} |
} |
1919 |
token->type = ANCHOR; |
token->type = ANCHOR; |
1920 |
token->opr.ctx_type = LINE_FIRST; |
token->opr.ctx_type = LINE_FIRST; |
1921 |
break; |
break; |
1922 |
case '$': |
case '$': |
1923 |
if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && |
if (!(syntax & REG_CONTEXT_INDEP_ANCHORS) && |
1924 |
re_string_cur_idx (input) + 1 != re_string_length (input)) |
re_string_cur_idx (input) + 1 != re_string_length (input)) |
1925 |
{ |
{ |
1926 |
re_token_t next; |
re_token_t next; |
1943 |
We must not use this function out of bracket expressions. */ |
We must not use this function out of bracket expressions. */ |
1944 |
|
|
1945 |
static int |
static int |
1946 |
peek_token_bracket (token, input, syntax) |
peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
|
re_token_t *token; |
|
|
re_string_t *input; |
|
|
reg_syntax_t syntax; |
|
1947 |
{ |
{ |
1948 |
unsigned char c; |
unsigned char c; |
1949 |
if (re_string_eoi (input)) |
if (re_string_eoi (input)) |
1963 |
} |
} |
1964 |
#endif /* RE_ENABLE_I18N */ |
#endif /* RE_ENABLE_I18N */ |
1965 |
|
|
1966 |
if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) |
if (c == '\\' && (syntax & REG_BACKSLASH_ESCAPE_IN_LISTS) |
1967 |
&& re_string_cur_idx (input) + 1 < re_string_length (input)) |
&& re_string_cur_idx (input) + 1 < re_string_length (input)) |
1968 |
{ |
{ |
1969 |
/* In this case, '\' escape a character. */ |
/* In this case, '\' escape a character. */ |
1993 |
token->type = OP_OPEN_EQUIV_CLASS; |
token->type = OP_OPEN_EQUIV_CLASS; |
1994 |
break; |
break; |
1995 |
case ':': |
case ':': |
1996 |
if (syntax & RE_CHAR_CLASSES) |
if (syntax & REG_CHAR_CLASSES) |
1997 |
{ |
{ |
1998 |
token->type = OP_OPEN_CHAR_CLASS; |
token->type = OP_OPEN_CHAR_CLASS; |
1999 |
break; |
break; |
2039 |
EOR means end of regular expression. */ |
EOR means end of regular expression. */ |
2040 |
|
|
2041 |
static bin_tree_t * |
static bin_tree_t * |
2042 |
parse (regexp, preg, syntax, err) |
parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, |
2043 |
re_string_t *regexp; |
reg_errcode_t *err) |
|
regex_t *preg; |
|
|
reg_syntax_t syntax; |
|
|
reg_errcode_t *err; |
|
2044 |
{ |
{ |
2045 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
2046 |
bin_tree_t *tree, *eor, *root; |
bin_tree_t *tree, *eor, *root; |
2047 |
re_token_t current_token; |
re_token_t current_token; |
2048 |
dfa->syntax = syntax; |
dfa->syntax = syntax; |
2049 |
fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); |
fetch_token (¤t_token, regexp, syntax | REG_CARET_ANCHORS_HERE); |
2050 |
tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); |
tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); |
2051 |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
2052 |
return NULL; |
return NULL; |
2073 |
ALT means alternative, which represents the operator `|'. */ |
ALT means alternative, which represents the operator `|'. */ |
2074 |
|
|
2075 |
static bin_tree_t * |
static bin_tree_t * |
2076 |
parse_reg_exp (regexp, preg, token, syntax, nest, err) |
parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, |
2077 |
re_string_t *regexp; |
reg_syntax_t syntax, Idx nest, reg_errcode_t *err) |
|
regex_t *preg; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
int nest; |
|
|
reg_errcode_t *err; |
|
2078 |
{ |
{ |
2079 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
2080 |
bin_tree_t *tree, *branch = NULL; |
bin_tree_t *tree, *branch = NULL; |
2081 |
tree = parse_branch (regexp, preg, token, syntax, nest, err); |
tree = parse_branch (regexp, preg, token, syntax, nest, err); |
2082 |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
2084 |
|
|
2085 |
while (token->type == OP_ALT) |
while (token->type == OP_ALT) |
2086 |
{ |
{ |
2087 |
fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); |
fetch_token (token, regexp, syntax | REG_CARET_ANCHORS_HERE); |
2088 |
if (token->type != OP_ALT && token->type != END_OF_RE |
if (token->type != OP_ALT && token->type != END_OF_RE |
2089 |
&& (nest == 0 || token->type != OP_CLOSE_SUBEXP)) |
&& (nest == 0 || token->type != OP_CLOSE_SUBEXP)) |
2090 |
{ |
{ |
2114 |
CAT means concatenation. */ |
CAT means concatenation. */ |
2115 |
|
|
2116 |
static bin_tree_t * |
static bin_tree_t * |
2117 |
parse_branch (regexp, preg, token, syntax, nest, err) |
parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, |
2118 |
re_string_t *regexp; |
reg_syntax_t syntax, Idx nest, reg_errcode_t *err) |
|
regex_t *preg; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
int nest; |
|
|
reg_errcode_t *err; |
|
2119 |
{ |
{ |
2120 |
bin_tree_t *tree, *exp; |
bin_tree_t *tree, *exp; |
2121 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
2122 |
tree = parse_expression (regexp, preg, token, syntax, nest, err); |
tree = parse_expression (regexp, preg, token, syntax, nest, err); |
2123 |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
2124 |
return NULL; |
return NULL; |
2154 |
*/ |
*/ |
2155 |
|
|
2156 |
static bin_tree_t * |
static bin_tree_t * |
2157 |
parse_expression (regexp, preg, token, syntax, nest, err) |
parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, |
2158 |
re_string_t *regexp; |
reg_syntax_t syntax, Idx nest, reg_errcode_t *err) |
|
regex_t *preg; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
int nest; |
|
|
reg_errcode_t *err; |
|
2159 |
{ |
{ |
2160 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
2161 |
bin_tree_t *tree; |
bin_tree_t *tree; |
2162 |
switch (token->type) |
switch (token->type) |
2163 |
{ |
{ |
2214 |
dfa->has_mb_node = 1; |
dfa->has_mb_node = 1; |
2215 |
break; |
break; |
2216 |
case OP_OPEN_DUP_NUM: |
case OP_OPEN_DUP_NUM: |
2217 |
if (syntax & RE_CONTEXT_INVALID_DUP) |
if (syntax & REG_CONTEXT_INVALID_DUP) |
2218 |
{ |
{ |
2219 |
*err = REG_BADRPT; |
*err = REG_BADRPT; |
2220 |
return NULL; |
return NULL; |
2223 |
case OP_DUP_ASTERISK: |
case OP_DUP_ASTERISK: |
2224 |
case OP_DUP_PLUS: |
case OP_DUP_PLUS: |
2225 |
case OP_DUP_QUESTION: |
case OP_DUP_QUESTION: |
2226 |
if (syntax & RE_CONTEXT_INVALID_OPS) |
if (syntax & REG_CONTEXT_INVALID_OPS) |
2227 |
{ |
{ |
2228 |
*err = REG_BADRPT; |
*err = REG_BADRPT; |
2229 |
return NULL; |
return NULL; |
2230 |
} |
} |
2231 |
else if (syntax & RE_CONTEXT_INDEP_OPS) |
else if (syntax & REG_CONTEXT_INDEP_OPS) |
2232 |
{ |
{ |
2233 |
fetch_token (token, regexp, syntax); |
fetch_token (token, regexp, syntax); |
2234 |
return parse_expression (regexp, preg, token, syntax, nest, err); |
return parse_expression (regexp, preg, token, syntax, nest, err); |
2236 |
/* else fall through */ |
/* else fall through */ |
2237 |
case OP_CLOSE_SUBEXP: |
case OP_CLOSE_SUBEXP: |
2238 |
if ((token->type == OP_CLOSE_SUBEXP) && |
if ((token->type == OP_CLOSE_SUBEXP) && |
2239 |
!(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) |
!(syntax & REG_UNMATCHED_RIGHT_PAREN_ORD)) |
2240 |
{ |
{ |
2241 |
*err = REG_ERPAREN; |
*err = REG_ERPAREN; |
2242 |
return NULL; |
return NULL; |
2350 |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
if (BE (*err != REG_NOERROR && tree == NULL, 0)) |
2351 |
return NULL; |
return NULL; |
2352 |
/* In BRE consecutive duplications are not allowed. */ |
/* In BRE consecutive duplications are not allowed. */ |
2353 |
if ((syntax & RE_CONTEXT_INVALID_DUP) |
if ((syntax & REG_CONTEXT_INVALID_DUP) |
2354 |
&& (token->type == OP_DUP_ASTERISK |
&& (token->type == OP_DUP_ASTERISK |
2355 |
|| token->type == OP_OPEN_DUP_NUM)) |
|| token->type == OP_OPEN_DUP_NUM)) |
2356 |
{ |
{ |
2370 |
*/ |
*/ |
2371 |
|
|
2372 |
static bin_tree_t * |
static bin_tree_t * |
2373 |
parse_sub_exp (regexp, preg, token, syntax, nest, err) |
parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, |
2374 |
re_string_t *regexp; |
reg_syntax_t syntax, Idx nest, reg_errcode_t *err) |
|
regex_t *preg; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
int nest; |
|
|
reg_errcode_t *err; |
|
2375 |
{ |
{ |
2376 |
re_dfa_t *dfa = (re_dfa_t *) preg->buffer; |
re_dfa_t *dfa = (re_dfa_t *) preg->re_buffer; |
2377 |
bin_tree_t *tree; |
bin_tree_t *tree; |
2378 |
size_t cur_nsub; |
size_t cur_nsub; |
2379 |
cur_nsub = preg->re_nsub++; |
cur_nsub = preg->re_nsub++; |
2380 |
|
|
2381 |
fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); |
fetch_token (token, regexp, syntax | REG_CARET_ANCHORS_HERE); |
2382 |
|
|
2383 |
/* The subexpression may be a null string. */ |
/* The subexpression may be a null string. */ |
2384 |
if (token->type == OP_CLOSE_SUBEXP) |
if (token->type == OP_CLOSE_SUBEXP) |
2391 |
if (BE (*err != REG_NOERROR, 0)) |
if (BE (*err != REG_NOERROR, 0)) |
2392 |
return NULL; |
return NULL; |
2393 |
} |
} |
2394 |
dfa->completed_bkref_map |= 1 << cur_nsub; |
|
2395 |
|
if (cur_nsub <= '9' - '1') |
2396 |
|
dfa->completed_bkref_map |= 1 << cur_nsub; |
2397 |
|
|
2398 |
tree = create_tree (dfa, tree, NULL, SUBEXP); |
tree = create_tree (dfa, tree, NULL, SUBEXP); |
2399 |
if (BE (tree == NULL, 0)) |
if (BE (tree == NULL, 0)) |
2408 |
/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ |
/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ |
2409 |
|
|
2410 |
static bin_tree_t * |
static bin_tree_t * |
2411 |
parse_dup_op (elem, regexp, dfa, token, syntax, err) |
parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, |
2412 |
bin_tree_t *elem; |
re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) |
|
re_string_t *regexp; |
|
|
re_dfa_t *dfa; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
reg_errcode_t *err; |
|
2413 |
{ |
{ |
2414 |
bin_tree_t *tree = NULL, *old_tree = NULL; |
bin_tree_t *tree = NULL, *old_tree = NULL; |
2415 |
int i, start, end, start_idx = re_string_cur_idx (regexp); |
Idx i, start, end, start_idx = re_string_cur_idx (regexp); |
2416 |
re_token_t start_token = *token; |
re_token_t start_token = *token; |
2417 |
|
|
2418 |
if (token->type == OP_OPEN_DUP_NUM) |
if (token->type == OP_OPEN_DUP_NUM) |
2419 |
{ |
{ |
2420 |
end = 0; |
end = 0; |
2421 |
start = fetch_number (regexp, token, syntax); |
start = fetch_number (regexp, token, syntax); |
2422 |
if (start == -1) |
if (start == REG_MISSING) |
2423 |
{ |
{ |
2424 |
if (token->type == CHARACTER && token->opr.c == ',') |
if (token->type == CHARACTER && token->opr.c == ',') |
2425 |
start = 0; /* We treat "{,m}" as "{0,m}". */ |
start = 0; /* We treat "{,m}" as "{0,m}". */ |
2429 |
return NULL; |
return NULL; |
2430 |
} |
} |
2431 |
} |
} |
2432 |
if (BE (start != -2, 1)) |
if (BE (start != REG_ERROR, 1)) |
2433 |
{ |
{ |
2434 |
/* We treat "{n}" as "{n,n}". */ |
/* We treat "{n}" as "{n,n}". */ |
2435 |
end = ((token->type == OP_CLOSE_DUP_NUM) ? start |
end = ((token->type == OP_CLOSE_DUP_NUM) ? start |
2436 |
: ((token->type == CHARACTER && token->opr.c == ',') |
: ((token->type == CHARACTER && token->opr.c == ',') |
2437 |
? fetch_number (regexp, token, syntax) : -2)); |
? fetch_number (regexp, token, syntax) : REG_ERROR)); |
2438 |
} |
} |
2439 |
if (BE (start == -2 || end == -2, 0)) |
if (BE (start == REG_ERROR || end == REG_ERROR, 0)) |
2440 |
{ |
{ |
2441 |
/* Invalid sequence. */ |
/* Invalid sequence. */ |
2442 |
if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) |
if (BE (!(syntax & REG_INVALID_INTERVAL_ORD), 0)) |
2443 |
{ |
{ |
2444 |
if (token->type == END_OF_RE) |
if (token->type == END_OF_RE) |
2445 |
*err = REG_EBRACE; |
*err = REG_EBRACE; |
2458 |
return elem; |
return elem; |
2459 |
} |
} |
2460 |
|
|
2461 |
if (BE (end != -1 && start > end, 0)) |
if (BE (end != REG_MISSING && start > end, 0)) |
2462 |
{ |
{ |
2463 |
/* First number greater than second. */ |
/* First number greater than second. */ |
2464 |
*err = REG_BADBR; |
*err = REG_BADBR; |
2468 |
else |
else |
2469 |
{ |
{ |
2470 |
start = (token->type == OP_DUP_PLUS) ? 1 : 0; |
start = (token->type == OP_DUP_PLUS) ? 1 : 0; |
2471 |
end = (token->type == OP_DUP_QUESTION) ? 1 : -1; |
end = (token->type == OP_DUP_QUESTION) ? 1 : REG_MISSING; |
2472 |
} |
} |
2473 |
|
|
2474 |
fetch_token (token, regexp, syntax); |
fetch_token (token, regexp, syntax); |
2506 |
if (elem->token.type == SUBEXP) |
if (elem->token.type == SUBEXP) |
2507 |
postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); |
postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); |
2508 |
|
|
2509 |
tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); |
tree = create_tree (dfa, elem, NULL, |
2510 |
|
(end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT)); |
2511 |
if (BE (tree == NULL, 0)) |
if (BE (tree == NULL, 0)) |
2512 |
goto parse_dup_op_espace; |
goto parse_dup_op_espace; |
2513 |
|
|
2514 |
/* This loop is actually executed only when end != -1, |
/* This loop is actually executed only when end != REG_MISSING, |
2515 |
to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have |
to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have |
2516 |
already created the start+1-th copy. */ |
already created the start+1-th copy. */ |
2517 |
for (i = start + 2; i <= end; ++i) |
if ((Idx) -1 < 0 || end != REG_MISSING) |
2518 |
{ |
for (i = start + 2; i <= end; ++i) |
2519 |
elem = duplicate_tree (elem, dfa); |
{ |
2520 |
tree = create_tree (dfa, tree, elem, CONCAT); |
elem = duplicate_tree (elem, dfa); |
2521 |
if (BE (elem == NULL || tree == NULL, 0)) |
tree = create_tree (dfa, tree, elem, CONCAT); |
2522 |
goto parse_dup_op_espace; |
if (BE (elem == NULL || tree == NULL, 0)) |
2523 |
|
goto parse_dup_op_espace; |
2524 |
tree = create_tree (dfa, tree, NULL, OP_ALT); |
|
2525 |
if (BE (tree == NULL, 0)) |
tree = create_tree (dfa, tree, NULL, OP_ALT); |
2526 |
goto parse_dup_op_espace; |
if (BE (tree == NULL, 0)) |
2527 |
} |
goto parse_dup_op_espace; |
2528 |
|
} |
2529 |
|
|
2530 |
if (old_tree) |
if (old_tree) |
2531 |
tree = create_tree (dfa, old_tree, tree, CONCAT); |
tree = create_tree (dfa, old_tree, tree, CONCAT); |
2550 |
update it. */ |
update it. */ |
2551 |
|
|
2552 |
static reg_errcode_t |
static reg_errcode_t |
2553 |
|
build_range_exp (re_bitset_ptr_t sbcset, |
2554 |
# ifdef RE_ENABLE_I18N |
# ifdef RE_ENABLE_I18N |
2555 |
build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) |
re_charset_t *mbcset, Idx *range_alloc, |
2556 |
re_charset_t *mbcset; |
# endif |
2557 |
int *range_alloc; |
bracket_elem_t *start_elem, bracket_elem_t *end_elem) |
|
# else /* not RE_ENABLE_I18N */ |
|
|
build_range_exp (sbcset, start_elem, end_elem) |
|
|
# endif /* not RE_ENABLE_I18N */ |
|
|
re_bitset_ptr_t sbcset; |
|
|
bracket_elem_t *start_elem, *end_elem; |
|
2558 |
{ |
{ |
2559 |
unsigned int start_ch, end_ch; |
unsigned int start_ch, end_ch; |
2560 |
/* Equivalence Classes and Character Classes can't be a range start/end. */ |
/* Equivalence Classes and Character Classes can't be a range start/end. */ |
2606 |
{ |
{ |
2607 |
/* There is not enough space, need realloc. */ |
/* There is not enough space, need realloc. */ |
2608 |
wchar_t *new_array_start, *new_array_end; |
wchar_t *new_array_start, *new_array_end; |
2609 |
int new_nranges; |
Idx new_nranges; |
2610 |
|
|
2611 |
/* +1 in case of mbcset->nranges is 0. */ |
new_nranges = mbcset->nranges; |
|
new_nranges = 2 * mbcset->nranges + 1; |
|
2612 |
/* Use realloc since mbcset->range_starts and mbcset->range_ends |
/* Use realloc since mbcset->range_starts and mbcset->range_ends |
2613 |
are NULL if *range_alloc == 0. */ |
are NULL if *range_alloc == 0. */ |
2614 |
new_array_start = re_realloc (mbcset->range_starts, wchar_t, |
new_array_start = re_x2realloc (mbcset->range_starts, wchar_t, |
2615 |
new_nranges); |
&new_nranges); |
2616 |
new_array_end = re_realloc (mbcset->range_ends, wchar_t, |
new_array_end = re_realloc (mbcset->range_ends, wchar_t, |
2617 |
new_nranges); |
new_nranges); |
2618 |
|
|
2666 |
pointer argument since we may update it. */ |
pointer argument since we may update it. */ |
2667 |
|
|
2668 |
static reg_errcode_t |
static reg_errcode_t |
2669 |
|
build_collating_symbol (re_bitset_ptr_t sbcset, |
2670 |
# ifdef RE_ENABLE_I18N |
# ifdef RE_ENABLE_I18N |
2671 |
build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) |
re_charset_t *mbcset, Idx *coll_sym_alloc, |
2672 |
re_charset_t *mbcset; |
# endif |
2673 |
int *coll_sym_alloc; |
const unsigned char *name) |
|
# else /* not RE_ENABLE_I18N */ |
|
|
build_collating_symbol (sbcset, name) |
|
|
# endif /* not RE_ENABLE_I18N */ |
|
|
re_bitset_ptr_t sbcset; |
|
|
const unsigned char *name; |
|
2674 |
{ |
{ |
2675 |
size_t name_len = strlen ((const char *) name); |
size_t name_len = strlen ((const char *) name); |
2676 |
if (BE (name_len != 1, 0)) |
if (BE (name_len != 1, 0)) |
2687 |
"[[.a-a.]]" etc. */ |
"[[.a-a.]]" etc. */ |
2688 |
|
|
2689 |
static bin_tree_t * |
static bin_tree_t * |
2690 |
parse_bracket_exp (regexp, dfa, token, syntax, err) |
parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
2691 |
re_string_t *regexp; |
reg_syntax_t syntax, reg_errcode_t *err) |
|
re_dfa_t *dfa; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
|
reg_errcode_t *err; |
|
2692 |
{ |
{ |
2693 |
#ifdef _LIBC |
#ifdef _LIBC |
2694 |
const unsigned char *collseqmb; |
const unsigned char *collseqmb; |
2704 |
|
|
2705 |
auto inline int32_t |
auto inline int32_t |
2706 |
__attribute ((always_inline)) |
__attribute ((always_inline)) |
2707 |
seek_collating_symbol_entry (name, name_len) |
seek_collating_symbol_entry (const unsigned char *name, size_t name_len) |
|
const unsigned char *name; |
|
|
size_t name_len; |
|
2708 |
{ |
{ |
2709 |
int32_t hash = elem_hash ((const char *) name, name_len); |
int32_t hash = elem_hash ((const char *) name, name_len); |
2710 |
int32_t elem = hash % table_size; |
int32_t elem = hash % table_size; |
2735 |
|
|
2736 |
auto inline unsigned int |
auto inline unsigned int |
2737 |
__attribute ((always_inline)) |
__attribute ((always_inline)) |
2738 |
lookup_collation_sequence_value (br_elem) |
lookup_collation_sequence_value (bracket_elem_t *br_elem) |
|
bracket_elem_t *br_elem; |
|
2739 |
{ |
{ |
2740 |
if (br_elem->type == SB_CHAR) |
if (br_elem->type == SB_CHAR) |
2741 |
{ |
{ |
2802 |
|
|
2803 |
auto inline reg_errcode_t |
auto inline reg_errcode_t |
2804 |
__attribute ((always_inline)) |
__attribute ((always_inline)) |
2805 |
build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) |
build_range_exp (re_bitset_ptr_t sbcset, re_charset_t *mbcset, |
2806 |
re_charset_t *mbcset; |
Idx *range_alloc, |
2807 |
int *range_alloc; |
bracket_elem_t *start_elem, bracket_elem_t *end_elem) |
|
re_bitset_ptr_t sbcset; |
|
|
bracket_elem_t *start_elem, *end_elem; |
|
2808 |
{ |
{ |
2809 |
unsigned int ch; |
unsigned int ch; |
2810 |
uint32_t start_collseq; |
uint32_t start_collseq; |
2822 |
/* Check start/end collation sequence values. */ |
/* Check start/end collation sequence values. */ |
2823 |
if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) |
if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) |
2824 |
return REG_ECOLLATE; |
return REG_ECOLLATE; |
2825 |
if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) |
if (BE ((syntax & REG_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) |
2826 |
return REG_ERANGE; |
return REG_ERANGE; |
2827 |
|
|
2828 |
/* Got valid collation sequence values, add them as a new entry. |
/* Got valid collation sequence values, add them as a new entry. |
2837 |
/* There is not enough space, need realloc. */ |
/* There is not enough space, need realloc. */ |
2838 |
uint32_t *new_array_start; |
uint32_t *new_array_start; |
2839 |
uint32_t *new_array_end; |
uint32_t *new_array_end; |
2840 |
int new_nranges; |
Idx new_nranges; |
2841 |
|
|
2842 |
/* +1 in case of mbcset->nranges is 0. */ |
new_nranges = mbcset->nranges; |
2843 |
new_nranges = 2 * mbcset->nranges + 1; |
new_array_start = re_x2realloc (mbcset->range_starts, uint32_t, |
2844 |
new_array_start = re_realloc (mbcset->range_starts, uint32_t, |
&new_nranges); |
|
new_nranges); |
|
2845 |
new_array_end = re_realloc (mbcset->range_ends, uint32_t, |
new_array_end = re_realloc (mbcset->range_ends, uint32_t, |
2846 |
new_nranges); |
new_nranges); |
2847 |
|
|
2882 |
|
|
2883 |
auto inline reg_errcode_t |
auto inline reg_errcode_t |
2884 |
__attribute ((always_inline)) |
__attribute ((always_inline)) |
2885 |
build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) |
build_collating_symbol (re_bitset_ptr_t sbcset, re_charset_t *mbcset, |
2886 |
re_charset_t *mbcset; |
Idx *coll_sym_alloc, const unsigned char *name) |
|
int *coll_sym_alloc; |
|
|
re_bitset_ptr_t sbcset; |
|
|
const unsigned char *name; |
|
2887 |
{ |
{ |
2888 |
int32_t elem, idx; |
int32_t elem, idx; |
2889 |
size_t name_len = strlen ((const char *) name); |
size_t name_len = strlen ((const char *) name); |
2912 |
if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) |
if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) |
2913 |
{ |
{ |
2914 |
/* Not enough, realloc it. */ |
/* Not enough, realloc it. */ |
2915 |
/* +1 in case of mbcset->ncoll_syms is 0. */ |
Idx new_coll_sym_alloc = mbcset->ncoll_syms; |
|
int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; |
|
2916 |
/* Use realloc since mbcset->coll_syms is NULL |
/* Use realloc since mbcset->coll_syms is NULL |
2917 |
if *alloc == 0. */ |
if *alloc == 0. */ |
2918 |
int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, |
int32_t *new_coll_syms = re_x2realloc (mbcset->coll_syms, int32_t, |
2919 |
new_coll_sym_alloc); |
&new_coll_sym_alloc); |
2920 |
if (BE (new_coll_syms == NULL, 0)) |
if (BE (new_coll_syms == NULL, 0)) |
2921 |
return REG_ESPACE; |
return REG_ESPACE; |
2922 |
mbcset->coll_syms = new_coll_syms; |
mbcset->coll_syms = new_coll_syms; |
2942 |
re_bitset_ptr_t sbcset; |
re_bitset_ptr_t sbcset; |
2943 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
2944 |
re_charset_t *mbcset; |
re_charset_t *mbcset; |
2945 |
int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; |
Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; |
2946 |
int equiv_class_alloc = 0, char_class_alloc = 0; |
Idx equiv_class_alloc = 0, char_class_alloc = 0; |
2947 |
#endif /* not RE_ENABLE_I18N */ |
#endif /* not RE_ENABLE_I18N */ |
2948 |
int non_match = 0; |
bool non_match = false; |
2949 |
bin_tree_t *work_tree; |
bin_tree_t *work_tree; |
2950 |
int token_len; |
int token_len; |
2951 |
int first_round = 1; |
bool first_round = true; |
2952 |
#ifdef _LIBC |
#ifdef _LIBC |
2953 |
collseqmb = (const unsigned char *) |
collseqmb = (const unsigned char *) |
2954 |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); |
2966 |
_NL_COLLATE_SYMB_EXTRAMB); |
_NL_COLLATE_SYMB_EXTRAMB); |
2967 |
} |
} |
2968 |
#endif |
#endif |
2969 |
sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); |
sbcset = re_calloc (unsigned int, BITSET_UINTS); |
2970 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
2971 |
mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); |
mbcset = re_calloc (re_charset_t, 1); |
2972 |
#endif /* RE_ENABLE_I18N */ |
#endif /* RE_ENABLE_I18N */ |
2973 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
2974 |
if (BE (sbcset == NULL || mbcset == NULL, 0)) |
if (BE (sbcset == NULL || mbcset == NULL, 0)) |
2991 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
2992 |
mbcset->non_match = 1; |
mbcset->non_match = 1; |
2993 |
#endif /* not RE_ENABLE_I18N */ |
#endif /* not RE_ENABLE_I18N */ |
2994 |
non_match = 1; |
non_match = true; |
2995 |
if (syntax & RE_HAT_LISTS_NOT_NEWLINE) |
if (syntax & REG_HAT_LISTS_NOT_NEWLINE) |
2996 |
bitset_set (sbcset, '\0'); |
bitset_set (sbcset, '\0'); |
2997 |
re_string_skip_bytes (regexp, token_len); /* Skip a token. */ |
re_string_skip_bytes (regexp, token_len); /* Skip a token. */ |
2998 |
token_len = peek_token_bracket (token, regexp, syntax); |
token_len = peek_token_bracket (token, regexp, syntax); |
3013 |
unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; |
unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; |
3014 |
unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; |
unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; |
3015 |
reg_errcode_t ret; |
reg_errcode_t ret; |
3016 |
int token_len2 = 0, is_range_exp = 0; |
int token_len2 = 0; |
3017 |
|
bool is_range_exp = false; |
3018 |
re_token_t token2; |
re_token_t token2; |
3019 |
|
|
3020 |
start_elem.opr.name = start_name_buf; |
start_elem.opr.name = start_name_buf; |
3025 |
*err = ret; |
*err = ret; |
3026 |
goto parse_bracket_exp_free_return; |
goto parse_bracket_exp_free_return; |
3027 |
} |
} |
3028 |
first_round = 0; |
first_round = false; |
3029 |
|
|
3030 |
/* Get information about the next token. We need it in any case. */ |
/* Get information about the next token. We need it in any case. */ |
3031 |
token_len = peek_token_bracket (token, regexp, syntax); |
token_len = peek_token_bracket (token, regexp, syntax); |
3054 |
token->type = CHARACTER; |
token->type = CHARACTER; |
3055 |
} |
} |
3056 |
else |
else |
3057 |
is_range_exp = 1; |
is_range_exp = true; |
3058 |
} |
} |
3059 |
} |
} |
3060 |
|
|
3061 |
if (is_range_exp == 1) |
if (is_range_exp == true) |
3062 |
{ |
{ |
3063 |
end_elem.opr.name = end_name_buf; |
end_elem.opr.name = end_name_buf; |
3064 |
ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, |
ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, |
3065 |
dfa, syntax, 1); |
dfa, syntax, true); |
3066 |
if (BE (ret != REG_NOERROR, 0)) |
if (BE (ret != REG_NOERROR, 0)) |
3067 |
{ |
{ |
3068 |
*err = ret; |
*err = ret; |
3100 |
{ |
{ |
3101 |
wchar_t *new_mbchars; |
wchar_t *new_mbchars; |
3102 |
/* Not enough, realloc it. */ |
/* Not enough, realloc it. */ |
3103 |
/* +1 in case of mbcset->nmbchars is 0. */ |
mbchar_alloc = mbcset->nmbchars; |
|
mbchar_alloc = 2 * mbcset->nmbchars + 1; |
|
3104 |
/* Use realloc since array is NULL if *alloc == 0. */ |
/* Use realloc since array is NULL if *alloc == 0. */ |
3105 |
new_mbchars = re_realloc (mbcset->mbchars, wchar_t, |
new_mbchars = re_x2realloc (mbcset->mbchars, wchar_t, |
3106 |
mbchar_alloc); |
&mbchar_alloc); |
3107 |
if (BE (new_mbchars == NULL, 0)) |
if (BE (new_mbchars == NULL, 0)) |
3108 |
goto parse_bracket_exp_espace; |
goto parse_bracket_exp_espace; |
3109 |
mbcset->mbchars = new_mbchars; |
mbcset->mbchars = new_mbchars; |
3229 |
/* Parse an element in the bracket expression. */ |
/* Parse an element in the bracket expression. */ |
3230 |
|
|
3231 |
static reg_errcode_t |
static reg_errcode_t |
3232 |
parse_bracket_element (elem, regexp, token, token_len, dfa, syntax, |
parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, |
3233 |
accept_hyphen) |
re_token_t *token, int token_len, re_dfa_t *dfa, |
3234 |
bracket_elem_t *elem; |
reg_syntax_t syntax, bool accept_hyphen) |
|
re_string_t *regexp; |
|
|
re_token_t *token; |
|
|
int token_len; |
|
|
re_dfa_t *dfa; |
|
|
reg_syntax_t syntax; |
|
|
int accept_hyphen; |
|
3235 |
{ |
{ |
3236 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3237 |
int cur_char_size; |
int cur_char_size; |
3269 |
[=<equivalent_class>=]. */ |
[=<equivalent_class>=]. */ |
3270 |
|
|
3271 |
static reg_errcode_t |
static reg_errcode_t |
3272 |
parse_bracket_symbol (elem, regexp, token) |
parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, |
3273 |
bracket_elem_t *elem; |
re_token_t *token) |
|
re_string_t *regexp; |
|
|
re_token_t *token; |
|
3274 |
{ |
{ |
3275 |
unsigned char ch, delim = token->opr.c; |
unsigned char ch, delim = token->opr.c; |
3276 |
int i = 0; |
int i = 0; |
3316 |
is a pointer argument sinse we may update it. */ |
is a pointer argument sinse we may update it. */ |
3317 |
|
|
3318 |
static reg_errcode_t |
static reg_errcode_t |
3319 |
|
build_equiv_class (re_bitset_ptr_t sbcset, |
3320 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3321 |
build_equiv_class (sbcset, mbcset, equiv_class_alloc, name) |
re_charset_t *mbcset, Idx *equiv_class_alloc, |
3322 |
re_charset_t *mbcset; |
#endif |
3323 |
int *equiv_class_alloc; |
const unsigned char *name) |
|
#else /* not RE_ENABLE_I18N */ |
|
|
build_equiv_class (sbcset, name) |
|
|
#endif /* not RE_ENABLE_I18N */ |
|
|
re_bitset_ptr_t sbcset; |
|
|
const unsigned char *name; |
|
3324 |
{ |
{ |
3325 |
#if defined _LIBC |
#if defined _LIBC |
3326 |
uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
3377 |
if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) |
if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) |
3378 |
{ |
{ |
3379 |
/* Not enough, realloc it. */ |
/* Not enough, realloc it. */ |
3380 |
/* +1 in case of mbcset->nequiv_classes is 0. */ |
Idx new_equiv_class_alloc = mbcset->nequiv_classes; |
|
int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; |
|
3381 |
/* Use realloc since the array is NULL if *alloc == 0. */ |
/* Use realloc since the array is NULL if *alloc == 0. */ |
3382 |
int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, |
int32_t *new_equiv_classes = re_x2realloc (mbcset->equiv_classes, |
3383 |
int32_t, |
int32_t, |
3384 |
new_equiv_class_alloc); |
&new_equiv_class_alloc); |
3385 |
if (BE (new_equiv_classes == NULL, 0)) |
if (BE (new_equiv_classes == NULL, 0)) |
3386 |
return REG_ESPACE; |
return REG_ESPACE; |
3387 |
mbcset->equiv_classes = new_equiv_classes; |
mbcset->equiv_classes = new_equiv_classes; |
3406 |
is a pointer argument sinse we may update it. */ |
is a pointer argument sinse we may update it. */ |
3407 |
|
|
3408 |
static reg_errcode_t |
static reg_errcode_t |
3409 |
|
build_charclass (unsigned REG_TRANSLATE_TYPE trans, re_bitset_ptr_t sbcset, |
3410 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3411 |
build_charclass (trans, sbcset, mbcset, char_class_alloc, class_name, syntax) |
re_charset_t *mbcset, Idx *char_class_alloc, |
3412 |
re_charset_t *mbcset; |
#endif |
3413 |
int *char_class_alloc; |
const unsigned char *class_name, reg_syntax_t syntax) |
|
#else /* not RE_ENABLE_I18N */ |
|
|
build_charclass (trans, sbcset, class_name, syntax) |
|
|
#endif /* not RE_ENABLE_I18N */ |
|
|
unsigned RE_TRANSLATE_TYPE trans; |
|
|
re_bitset_ptr_t sbcset; |
|
|
const unsigned char *class_name; |
|
|
reg_syntax_t syntax; |
|
3414 |
{ |
{ |
3415 |
int i; |
int i; |
3416 |
const char *name = (const char *) class_name; |
const char *name = (const char *) class_name; |
3417 |
|
|
3418 |
/* In case of REG_ICASE "upper" and "lower" match the both of |
/* In case of REG_ICASE "upper" and "lower" match the both of |
3419 |
upper and lower cases. */ |
upper and lower cases. */ |
3420 |
if ((syntax & RE_ICASE) |
if ((syntax & REG_IGNORE_CASE) |
3421 |
&& (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) |
&& (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) |
3422 |
name = "alpha"; |
name = "alpha"; |
3423 |
|
|
3426 |
if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) |
if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) |
3427 |
{ |
{ |
3428 |
/* Not enough, realloc it. */ |
/* Not enough, realloc it. */ |
3429 |
/* +1 in case of mbcset->nchar_classes is 0. */ |
Idx new_char_class_alloc = mbcset->nchar_classes; |
|
int new_char_class_alloc = 2 * mbcset->nchar_classes + 1; |
|
3430 |
/* Use realloc since array is NULL if *alloc == 0. */ |
/* Use realloc since array is NULL if *alloc == 0. */ |
3431 |
wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, |
wctype_t *new_char_classes = re_x2realloc (mbcset->char_classes, wctype_t, |
3432 |
new_char_class_alloc); |
&new_char_class_alloc); |
3433 |
if (BE (new_char_classes == NULL, 0)) |
if (BE (new_char_classes == NULL, 0)) |
3434 |
return REG_ESPACE; |
return REG_ESPACE; |
3435 |
mbcset->char_classes = new_char_classes; |
mbcset->char_classes = new_char_classes; |
3479 |
} |
} |
3480 |
|
|
3481 |
static bin_tree_t * |
static bin_tree_t * |
3482 |
build_charclass_op (dfa, trans, class_name, extra, non_match, err) |
build_charclass_op (re_dfa_t *dfa, unsigned REG_TRANSLATE_TYPE trans, |
3483 |
re_dfa_t *dfa; |
const unsigned char *class_name, |
3484 |
unsigned RE_TRANSLATE_TYPE trans; |
const unsigned char *extra, |
3485 |
const unsigned char *class_name; |
bool non_match, reg_errcode_t *err) |
|
const unsigned char *extra; |
|
|
int non_match; |
|
|
reg_errcode_t *err; |
|
3486 |
{ |
{ |
3487 |
re_bitset_ptr_t sbcset; |
re_bitset_ptr_t sbcset; |
3488 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3489 |
re_charset_t *mbcset; |
re_charset_t *mbcset; |
3490 |
int alloc = 0; |
Idx alloc = 0; |
3491 |
#endif /* not RE_ENABLE_I18N */ |
#endif /* not RE_ENABLE_I18N */ |
3492 |
reg_errcode_t ret; |
reg_errcode_t ret; |
3493 |
re_token_t br_token; |
re_token_t br_token; |
3494 |
bin_tree_t *tree; |
bin_tree_t *tree; |
3495 |
|
|
3496 |
sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); |
sbcset = re_calloc (unsigned int, BITSET_UINTS); |
3497 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3498 |
mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); |
mbcset = re_calloc (re_charset_t, 1); |
3499 |
#endif /* RE_ENABLE_I18N */ |
#endif /* RE_ENABLE_I18N */ |
3500 |
|
|
3501 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3512 |
{ |
{ |
3513 |
#ifdef RE_ENABLE_I18N |
#ifdef RE_ENABLE_I18N |
3514 |
/* |
/* |
3515 |
if (syntax & RE_HAT_LISTS_NOT_NEWLINE) |
if (syntax & REG_HAT_LISTS_NOT_NEWLINE) |
3516 |
bitset_set(cset->sbcset, '\0'); |
bitset_set(cset->sbcset, '\0'); |
3517 |
*/ |
*/ |
3518 |
mbcset->non_match = 1; |
mbcset->non_match = 1; |
3592 |
|
|
3593 |
/* This is intended for the expressions like "a{1,3}". |
/* This is intended for the expressions like "a{1,3}". |
3594 |
Fetch a number from `input', and return the number. |
Fetch a number from `input', and return the number. |
3595 |
Return -1, if the number field is empty like "{,1}". |
Return REG_MISSING if the number field is empty like "{,1}". |
3596 |
Return -2, If an error is occured. */ |
Return REG_ERROR if an error occurred. */ |
3597 |
|
|
3598 |
static int |
static Idx |
3599 |
fetch_number (input, token, syntax) |
fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) |
|
re_string_t *input; |
|
|
re_token_t *token; |
|
|
reg_syntax_t syntax; |
|
3600 |
{ |
{ |
3601 |
int num = -1; |
Idx num = REG_MISSING; |
3602 |
unsigned char c; |
unsigned char c; |
3603 |
while (1) |
while (1) |
3604 |
{ |
{ |
3605 |
fetch_token (token, input, syntax); |
fetch_token (token, input, syntax); |
3606 |
c = token->opr.c; |
c = token->opr.c; |
3607 |
if (BE (token->type == END_OF_RE, 0)) |
if (BE (token->type == END_OF_RE, 0)) |
3608 |
return -2; |
return REG_ERROR; |
3609 |
if (token->type == OP_CLOSE_DUP_NUM || c == ',') |
if (token->type == OP_CLOSE_DUP_NUM || c == ',') |
3610 |
break; |
break; |
3611 |
num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) |
num = ((token->type != CHARACTER || c < '0' || '9' < c |
3612 |
? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0')); |
|| num == REG_ERROR) |
3613 |
num = (num > RE_DUP_MAX) ? -2 : num; |
? REG_ERROR |
3614 |
|
: ((num == REG_MISSING) ? c - '0' : num * 10 + c - '0')); |
3615 |
|
num = (num > REG_DUP_MAX) ? REG_ERROR : num; |
3616 |
} |
} |
3617 |
return num; |
return num; |
3618 |
} |
} |
3638 |
/* Create a tree node. */ |
/* Create a tree node. */ |
3639 |
|
|
3640 |
static bin_tree_t * |
static bin_tree_t * |
3641 |
create_tree (dfa, left, right, type) |
create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, |
3642 |
re_dfa_t *dfa; |
re_token_type_t type) |
|
bin_tree_t *left; |
|
|
bin_tree_t *right; |
|
|
re_token_type_t type; |
|
3643 |
{ |
{ |
3644 |
re_token_t t; |
re_token_t t; |
3645 |
t.type = type; |
t.type = type; |
3647 |
} |
} |
3648 |
|
|
3649 |
static bin_tree_t * |
static bin_tree_t * |
3650 |
create_token_tree (dfa, left, right, token) |
create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, |
3651 |
re_dfa_t *dfa; |
const re_token_t *token) |
|
bin_tree_t *left; |
|
|
bin_tree_t *right; |
|
|
const re_token_t *token; |
|
3652 |
{ |
{ |
3653 |
bin_tree_t *tree; |
bin_tree_t *tree; |
3654 |
if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) |
if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) |
3671 |
tree->token.opt_subexp = 0; |
tree->token.opt_subexp = 0; |
3672 |
tree->first = NULL; |
tree->first = NULL; |
3673 |
tree->next = NULL; |
tree->next = NULL; |
3674 |
tree->node_idx = -1; |
tree->node_idx = REG_MISSING; |
3675 |
|
|
3676 |
if (left != NULL) |
if (left != NULL) |
3677 |
left->parent = tree; |
left->parent = tree; |
3684 |
To be called from preorder or postorder. */ |
To be called from preorder or postorder. */ |
3685 |
|
|
3686 |
static reg_errcode_t |
static reg_errcode_t |
3687 |
mark_opt_subexp (extra, node) |
mark_opt_subexp (void *extra, bin_tree_t *node) |
|
void *extra; |
|
|
bin_tree_t *node; |
|
3688 |
{ |
{ |
3689 |
int idx = (int) (long) extra; |
Idx idx = (Idx) (long) extra; |
3690 |
if (node->token.type == SUBEXP && node->token.opr.idx == idx) |
if (node->token.type == SUBEXP && node->token.opr.idx == idx) |
3691 |
node->token.opt_subexp = 1; |
node->token.opt_subexp = 1; |
3692 |
|
|
3724 |
it's easier to duplicate. */ |
it's easier to duplicate. */ |
3725 |
|
|
3726 |
static bin_tree_t * |
static bin_tree_t * |
3727 |
duplicate_tree (root, dfa) |
duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) |
|
const bin_tree_t *root; |
|
|
re_dfa_t *dfa; |
|
3728 |
{ |
{ |
3729 |
const bin_tree_t *node; |
const bin_tree_t *node; |
3730 |
bin_tree_t *dup_root; |
bin_tree_t *dup_root; |