File Coverage

regex_internal.c
Criterion Covered Total %
statement 496 757 65.5
branch 295 654 45.1
condition n/a
subroutine n/a
pod n/a
total 791 1411 56.0


line stmt bran cond sub pod time code
1             /* Extended regular expression matching and search library.
2             Copyright (C) 2002-2014 Free Software Foundation, Inc.
3             This file is part of the GNU C Library.
4             Contributed by Isamu Hasegawa .
5              
6             The GNU C Library is free software; you can redistribute it and/or
7             modify it under the terms of the GNU Lesser General Public
8             License as published by the Free Software Foundation; either
9             version 2.1 of the License, or (at your option) any later version.
10              
11             The GNU C Library is distributed in the hope that it will be useful,
12             but WITHOUT ANY WARRANTY; without even the implied warranty of
13             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14             Lesser General Public License for more details.
15              
16             You should have received a copy of the GNU Lesser General Public
17             License along with the GNU C Library; if not, see
18             . */
19              
20             static void re_string_construct_common (pTHX_ const char *str, Idx len,
21             re_string_t *pstr,
22             RE_TRANSLATE_TYPE trans, bool icase,
23             const re_dfa_t *dfa) internal_function;
24             static re_dfastate_t *create_ci_newstate (pTHX_ const re_dfa_t *dfa,
25             const re_node_set *nodes,
26             re_hashval_t hash) internal_function;
27             static re_dfastate_t *create_cd_newstate (pTHX_ const re_dfa_t *dfa,
28             const re_node_set *nodes,
29             unsigned int context,
30             re_hashval_t hash) internal_function;
31            
32             /* Functions for string operation. */
33              
34             /* This function allocate the buffers. It is necessary to call
35             re_string_reconstruct before using the object. */
36              
37             static reg_errcode_t
38             internal_function __attribute_warn_unused_result__
39 14           re_string_allocate (pTHX_ re_string_t *pstr, const char *str, Idx len, Idx init_len,
40             RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
41             {
42             reg_errcode_t ret;
43             Idx init_buf_len;
44              
45             /* Ensure at least one character fits into the buffers. */
46 14 100         if (init_len < dfa->mb_cur_max)
47 3           init_len = dfa->mb_cur_max;
48 14           init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
49 14           re_string_construct_common (aTHX_ str, len, pstr, trans, icase, dfa);
50              
51 14           ret = re_string_realloc_buffers (aTHX_ pstr, init_buf_len);
52 14 50         if (BE (ret != REG_NOERROR, 0))
53 0           return ret;
54              
55 14           pstr->word_char = dfa->word_char;
56 14           pstr->word_ops_used = dfa->word_ops_used;
57 14 100         pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
58 14 100         pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
    50          
59 14           pstr->valid_raw_len = pstr->valid_len;
60 14           return REG_NOERROR;
61             }
62              
63             /* This function allocate the buffers, and initialize them. */
64              
65             static reg_errcode_t
66             internal_function __attribute_warn_unused_result__
67 6           re_string_construct (pTHX_ re_string_t *pstr, const char *str, Idx len,
68             RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa)
69             {
70             reg_errcode_t ret;
71 6           memset (pstr, '\0', sizeof (re_string_t));
72 6           re_string_construct_common (aTHX_ str, len, pstr, trans, icase, dfa);
73              
74 6 50         if (len > 0)
75             {
76 6           ret = re_string_realloc_buffers (aTHX_ pstr, len + 1);
77 6 50         if (BE (ret != REG_NOERROR, 0))
78 0           return ret;
79             }
80 6 100         pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
81              
82 6 100         if (icase)
83             {
84             #ifdef RE_ENABLE_I18N
85 1 50         if (dfa->mb_cur_max > 1)
86             {
87             while (1)
88             {
89 1           ret = build_wcs_upper_buffer (aTHX_ pstr);
90 1 50         if (BE (ret != REG_NOERROR, 0))
91 0           return ret;
92 1 50         if (pstr->valid_raw_len >= len)
93 1           break;
94 0 0         if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
95 0           break;
96 0           ret = re_string_realloc_buffers (aTHX_ pstr, pstr->bufs_len * 2);
97 0 0         if (BE (ret != REG_NOERROR, 0))
98 0           return ret;
99 1           }
100             }
101             else
102             #endif /* RE_ENABLE_I18N */
103 1           build_upper_buffer (aTHX_ pstr);
104             }
105             else
106             {
107             #ifdef RE_ENABLE_I18N
108 5 50         if (dfa->mb_cur_max > 1)
109 5           build_wcs_buffer (aTHX_ pstr);
110             else
111             #endif /* RE_ENABLE_I18N */
112             {
113 0 0         if (trans != NULL)
114 0           re_string_translate_buffer (aTHX_ pstr);
115             else
116             {
117 0           pstr->valid_len = pstr->bufs_len;
118 0           pstr->valid_raw_len = pstr->bufs_len;
119             }
120             }
121             }
122              
123 6           return REG_NOERROR;
124             }
125              
126             /* Helper functions for re_string_allocate, and re_string_construct. */
127              
128             static reg_errcode_t
129             internal_function __attribute_warn_unused_result__
130 20           re_string_realloc_buffers (pTHX_ re_string_t *pstr, Idx new_buf_len)
131             {
132             #ifdef RE_ENABLE_I18N
133 20 50         if (pstr->mb_cur_max > 1)
134             {
135             /* Avoid overflow in realloc. */
136 20           const size_t max_object_size = MAX (sizeof (rpl__wint_t), sizeof (Idx));
137 20 50         if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_buf_len, 0))
138 0           return REG_ESPACE;
139              
140 20 50         re_realloc (pstr->wcs, rpl__wint_t, new_buf_len);
141 20 50         if (pstr->offsets != NULL)
142             {
143 0 0         re_realloc (pstr->offsets, Idx, new_buf_len);
144             }
145             }
146             #endif /* RE_ENABLE_I18N */
147 20 100         if (pstr->mbs_allocated)
148             {
149 2           re_realloc (pstr->mbs, unsigned char, new_buf_len);
150             }
151 20           pstr->bufs_len = new_buf_len;
152 20           return REG_NOERROR;
153             }
154              
155              
156             static void
157             internal_function
158 20           re_string_construct_common (pTHX_ const char *str, Idx len, re_string_t *pstr,
159             RE_TRANSLATE_TYPE trans, bool icase,
160             const re_dfa_t *dfa)
161             {
162 20           pstr->raw_mbs = (const unsigned char *) str;
163 20           pstr->len = len;
164 20           pstr->raw_len = len;
165 20           pstr->trans = trans;
166 20           pstr->icase = icase;
167 20 50         pstr->mbs_allocated = (trans != NULL || icase);
    100          
168 20           pstr->mb_cur_max = dfa->mb_cur_max;
169 20           pstr->is_utf8 = dfa->is_utf8;
170 20           pstr->map_notascii = dfa->map_notascii;
171 20           pstr->stop = pstr->len;
172 20           pstr->raw_stop = pstr->stop;
173 20           }
174              
175             #ifdef RE_ENABLE_I18N
176              
177             /* Build wide character buffer PSTR->WCS.
178             If the byte sequence of the string are:
179             (0), (1), (0), (1),
180             Then wide character buffer will be:
181             , rpl__WEOF , , rpl__WEOF ,
182             We use rpl__WEOF for padding, they indicate that the position isn't
183             a first byte of a multibyte character.
184              
185             Note that this function assumes PSTR->VALID_LEN elements are already
186             built and starts from PSTR->VALID_LEN. */
187              
188             static void
189             internal_function
190 40           build_wcs_buffer (pTHX_ re_string_t *pstr)
191             {
192             rpl__mbstate_t prev_st;
193             Idx byte_idx, end_idx, remain_len;
194             size_t mbclen;
195             #if (defined(_LIBC) || defined(_PERL_I18N))
196             unsigned char buf[rpl__MB_LEN_MAX];
197             assert (rpl__MB_LEN_MAX >= pstr->mb_cur_max);
198             #else
199             unsigned char buf[64];
200             #endif
201              
202             /* Build the buffers from pstr->valid_len to either pstr->len or
203             pstr->bufs_len. */
204 40           end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
205 152 100         for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
206             {
207             rpl__wchar_t wc;
208             const char *p;
209              
210 112           remain_len = end_idx - byte_idx;
211 112           prev_st = pstr->cur_state;
212             /* Apply the translation if we need. */
213 112 50         if (BE (pstr->trans != NULL, 0))
214             {
215             int i, ch;
216              
217 0 0         for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
    0          
218             {
219 0           ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
220 0           buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
221             }
222 0           p = (const char *) buf;
223             }
224             else
225 112           p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
226 112           mbclen = rpl__mbrtowc (&wc, p, remain_len, &pstr->cur_state);
227 112 50         if (BE (mbclen == (size_t) -1 || mbclen == 0
    50          
    50          
    50          
    0          
    50          
228             || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len), 0))
229             {
230             /* We treat these cases as a singlebyte character. */
231 0           mbclen = 1;
232 0           wc = (rpl__wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
233 0 0         if (BE (pstr->trans != NULL, 0))
234 0           wc = pstr->trans[wc];
235 0           pstr->cur_state = prev_st;
236             }
237 112 50         else if (BE (mbclen == (size_t) -2, 0))
238             {
239             /* The buffer doesn't have enough space, finish to build. */
240 0           pstr->cur_state = prev_st;
241 0           break;
242             }
243              
244             /* Write wide character and padding. */
245 112           pstr->wcs[byte_idx++] = wc;
246             /* Write paddings. */
247 200 100         for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
248 88           pstr->wcs[byte_idx++] = rpl__WEOF;
249             }
250 40           pstr->valid_len = byte_idx;
251 40           pstr->valid_raw_len = byte_idx;
252 40           }
253              
254             /* Build wide character buffer PSTR->WCS like build_wcs_buffer,
255             but for REG_ICASE. */
256              
257             static reg_errcode_t
258             internal_function __attribute_warn_unused_result__
259 17           build_wcs_upper_buffer (pTHX_ re_string_t *pstr)
260             {
261             rpl__mbstate_t prev_st;
262             Idx src_idx, byte_idx, end_idx, remain_len;
263             size_t mbclen;
264             #if (defined(_LIBC) || defined(_PERL_I18N))
265             char buf[rpl__MB_LEN_MAX];
266             assert (rpl__MB_LEN_MAX >= pstr->mb_cur_max);
267             #else
268             char buf[64];
269             #endif
270              
271 17           byte_idx = pstr->valid_len;
272 17           end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
273              
274             /* The following optimization assumes that ASCII characters can be
275             mapped to wide characters with a simple cast. */
276 17 50         if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
    50          
    100          
277             {
278 30 100         while (byte_idx < end_idx)
279             {
280             rpl__wchar_t wc;
281              
282 24 100         if (rpl__isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
283 18 50         && rpl__mbsinit (&pstr->cur_state))
284             {
285             /* In case of a singlebyte character. */
286 18           pstr->mbs[byte_idx]
287 18           = rpl__toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
288             /* The next step uses the assumption that rpl__wchar_t is encoded
289             ASCII-safe: all ASCII values can be converted like this. */
290 18           pstr->wcs[byte_idx] = (rpl__wchar_t) pstr->mbs[byte_idx];
291 18           ++byte_idx;
292 18           continue;
293             }
294              
295 6           remain_len = end_idx - byte_idx;
296 6           prev_st = pstr->cur_state;
297 6           mbclen = rpl__mbrtowc (&wc,
298             ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
299             + byte_idx), remain_len, &pstr->cur_state);
300 6 100         if (BE (mbclen < (size_t) -2, 1))
301             {
302 2           rpl__wchar_t wcu = wc;
303 2 50         if (rpl__iswlower (wc))
304             {
305             size_t mbcdlen;
306              
307 2           wcu = rpl__towupper (wc);
308 2           mbcdlen = rpl__wcrtomb (buf, wcu, &prev_st);
309 2 50         if (BE (mbclen == mbcdlen, 1))
310 0           Copy (buf, pstr->mbs + byte_idx, mbclen, char);
311             else
312             {
313 2           src_idx = byte_idx;
314 2           goto offsets_needed;
315             }
316             }
317             else
318 0           Copy (pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, pstr->mbs + byte_idx, mbclen, char);
319 0           pstr->wcs[byte_idx++] = wcu;
320             /* Write paddings. */
321 0 0         for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
322 0           pstr->wcs[byte_idx++] = rpl__WEOF;
323             }
324 4 50         else if (mbclen == (size_t) -1 || mbclen == 0
    0          
325 0 0         || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
    0          
326 4           {
327             /* It is an invalid character, an incomplete character
328             at the end of the string, or '\0'. Just use the byte. */
329 4           int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
330 4           pstr->mbs[byte_idx] = ch;
331             /* And also cast it to wide char. */
332 4           pstr->wcs[byte_idx++] = (rpl__wchar_t) ch;
333 4 50         if (BE (mbclen == (size_t) -1, 0))
334 4           pstr->cur_state = prev_st;
335             }
336             else
337             {
338             /* The buffer doesn't have enough space, finish to build. */
339 0           pstr->cur_state = prev_st;
340 4           break;
341             }
342             }
343 6           pstr->valid_len = byte_idx;
344 6           pstr->valid_raw_len = byte_idx;
345 6           return REG_NOERROR;
346             }
347             else
348 21 100         for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
349             {
350             rpl__wchar_t wc;
351             const char *p;
352             offsets_needed:
353 12           remain_len = end_idx - byte_idx;
354 12           prev_st = pstr->cur_state;
355 12 50         if (BE (pstr->trans != NULL, 0))
356             {
357             int i, ch;
358              
359 0 0         for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
    0          
360             {
361 0           ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
362 0           buf[i] = pstr->trans[ch];
363             }
364 0           p = (const char *) buf;
365             }
366             else
367 12           p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
368 12           mbclen = rpl__mbrtowc (&wc, p, remain_len, &pstr->cur_state);
369 12 100         if (BE (mbclen < (size_t) -2, 1))
370             {
371 10           rpl__wchar_t wcu = wc;
372 10 100         if (rpl__iswlower (wc))
373             {
374             size_t mbcdlen;
375              
376 3           wcu = rpl__towupper (wc);
377 3           mbcdlen = rpl__wcrtomb ((char *) buf, wcu, &prev_st);
378 3 50         if (BE (mbclen == mbcdlen, 1))
379 0           Copy (buf, pstr->mbs + byte_idx, mbclen, char);
380 3 50         else if (mbcdlen != (size_t) -1)
381             {
382             size_t i;
383              
384 3 50         if (byte_idx + mbcdlen > pstr->bufs_len)
385             {
386 0           pstr->cur_state = prev_st;
387 0           break;
388             }
389              
390 3 100         if (pstr->offsets == NULL)
391             {
392 1 50         re_malloc (pstr->offsets, Idx, pstr->bufs_len);
393             }
394 3 100         if (!pstr->offsets_needed)
395             {
396 11 100         for (i = 0; i < (size_t) byte_idx; ++i)
397 9           pstr->offsets[i] = i;
398 2           pstr->offsets_needed = 1;
399             }
400              
401 3           Copy (buf, pstr->mbs + byte_idx, mbcdlen, char);
402 3           pstr->wcs[byte_idx] = wcu;
403 3           pstr->offsets[byte_idx] = src_idx;
404 3 50         for (i = 1; i < mbcdlen; ++i)
405             {
406 0           pstr->offsets[byte_idx + i]
407 0 0         = src_idx + (i < mbclen ? i : mbclen - 1);
408 0           pstr->wcs[byte_idx + i] = rpl__WEOF;
409             }
410 3           pstr->len += mbcdlen - mbclen;
411 3 50         if (pstr->raw_stop > src_idx)
412 3           pstr->stop += mbcdlen - mbclen;
413 3           end_idx = (pstr->bufs_len > pstr->len)
414 3           ? pstr->len : pstr->bufs_len;
415 3           byte_idx += mbcdlen;
416 3           src_idx += mbclen;
417 3           continue;
418             }
419             else
420 0           Copy (p, pstr->mbs + byte_idx, mbclen, char);
421             }
422             else
423 7           Copy (p, pstr->mbs + byte_idx, mbclen, char);
424              
425 7 50         if (BE (pstr->offsets_needed != 0, 0))
426             {
427             size_t i;
428 14 100         for (i = 0; i < mbclen; ++i)
429 7           pstr->offsets[byte_idx + i] = src_idx + i;
430             }
431 7           src_idx += mbclen;
432              
433 7           pstr->wcs[byte_idx++] = wcu;
434             /* Write paddings. */
435 7 50         for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
436 0           pstr->wcs[byte_idx++] = rpl__WEOF;
437             }
438 2 50         else if (mbclen == (size_t) -1 || mbclen == 0
    0          
439 0 0         || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
    0          
440 2           {
441             /* It is an invalid character or '\0'. Just use the byte. */
442 2           int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
443              
444 2 50         if (BE (pstr->trans != NULL, 0))
445 0           ch = pstr->trans [ch];
446 2           pstr->mbs[byte_idx] = ch;
447              
448 2 50         if (BE (pstr->offsets_needed != 0, 0))
449 2           pstr->offsets[byte_idx] = src_idx;
450 2           ++src_idx;
451              
452             /* And also cast it to wide char. */
453 2           pstr->wcs[byte_idx++] = (rpl__wchar_t) ch;
454 2 50         if (BE (mbclen == (size_t) -1, 0))
455 2           pstr->cur_state = prev_st;
456             }
457             else
458             {
459             /* The buffer doesn't have enough space, finish to build. */
460 0           pstr->cur_state = prev_st;
461 9           break;
462             }
463             }
464 11           pstr->valid_len = byte_idx;
465 11           pstr->valid_raw_len = src_idx;
466 17           return REG_NOERROR;
467             }
468              
469             /* Skip characters until the index becomes greater than NEW_RAW_IDX.
470             Return the index. */
471              
472             static Idx
473             internal_function
474 10           re_string_skip_chars (pTHX_ re_string_t *pstr, Idx new_raw_idx, rpl__wint_t *last_wc)
475             {
476             rpl__mbstate_t prev_st;
477             Idx rawbuf_idx;
478             size_t mbclen;
479 10           rpl__wint_t wc = rpl__WEOF;
480              
481             /* Skip the characters which are not necessary to check. */
482 46 100         for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
483             rawbuf_idx < new_raw_idx;)
484             {
485             rpl__wchar_t wc2;
486 36           Idx remain_len = pstr->raw_len - rawbuf_idx;
487 36           prev_st = pstr->cur_state;
488 36           mbclen = rpl__mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx,
489             remain_len, &pstr->cur_state);
490 36 50         if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
    50          
    50          
    50          
491             {
492             /* We treat these cases as a single byte character. */
493 0 0         if (mbclen == 0 || remain_len == 0)
    0          
494 0           wc = L'\0';
495             else
496 0           wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
497 0           mbclen = 1;
498 0           pstr->cur_state = prev_st;
499             }
500             else
501 36           wc = wc2;
502             /* Then proceed the next character. */
503 36           rawbuf_idx += mbclen;
504             }
505 10           *last_wc = wc;
506 10           return rawbuf_idx;
507             }
508             #endif /* RE_ENABLE_I18N */
509              
510             /* Build the buffer PSTR->MBS, and apply the translation if we need.
511             This function is used in case of REG_ICASE. */
512              
513             static void
514             internal_function
515 0           build_upper_buffer (pTHX_ re_string_t *pstr)
516             {
517             Idx char_idx, end_idx;
518 0           end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
519              
520 0 0         for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
521             {
522 0           int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
523 0 0         if (BE (pstr->trans != NULL, 0))
524 0           ch = pstr->trans[ch];
525 0 0         if (rpl__islower (ch))
526 0           pstr->mbs[char_idx] = rpl__toupper (ch);
527             else
528 0           pstr->mbs[char_idx] = ch;
529             }
530 0           pstr->valid_len = char_idx;
531 0           pstr->valid_raw_len = char_idx;
532 0           }
533              
534             /* Apply TRANS to the buffer in PSTR. */
535              
536             static void
537             internal_function
538 0           re_string_translate_buffer (pTHX_ re_string_t *pstr)
539             {
540             Idx buf_idx, end_idx;
541 0           end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
542              
543 0 0         for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
544             {
545 0           int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
546 0           pstr->mbs[buf_idx] = pstr->trans[ch];
547             }
548              
549 0           pstr->valid_len = buf_idx;
550 0           pstr->valid_raw_len = buf_idx;
551 0           }
552              
553             /* This function re-construct the buffers.
554             Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
555             convert to upper case in case of REG_ICASE, apply translation. */
556              
557             static reg_errcode_t
558             internal_function __attribute_warn_unused_result__
559 51           re_string_reconstruct (pTHX_ re_string_t *pstr, Idx idx, int eflags)
560             {
561             Idx offset;
562              
563 51 50         if (BE (pstr->raw_mbs_idx <= idx, 0))
564 51           offset = idx - pstr->raw_mbs_idx;
565             else
566             {
567             /* Reset buffer. */
568             #ifdef RE_ENABLE_I18N
569 0 0         if (pstr->mb_cur_max > 1)
570 0           memset (&pstr->cur_state, '\0', sizeof (rpl__mbstate_t));
571             #endif /* RE_ENABLE_I18N */
572 0           pstr->len = pstr->raw_len;
573 0           pstr->stop = pstr->raw_stop;
574 0           pstr->valid_len = 0;
575 0           pstr->raw_mbs_idx = 0;
576 0           pstr->valid_raw_len = 0;
577 0           pstr->offsets_needed = 0;
578 0 0         pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
579             : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
580 0 0         if (!pstr->mbs_allocated)
581 0           pstr->mbs = (unsigned char *) pstr->raw_mbs;
582 0           offset = idx;
583             }
584              
585 51 100         if (BE (offset != 0, 1))
586             {
587             /* Should the already checked characters be kept? */
588 45 100         if (BE (offset < pstr->valid_raw_len, 1))
589             {
590             /* Yes, move them to the front of the buffer. */
591             #ifdef RE_ENABLE_I18N
592 35 100         if (BE (pstr->offsets_needed, 0))
593             {
594 11           Idx low = 0, high = pstr->valid_len, mid;
595             do
596             {
597 31           mid = (high + low) / 2;
598 31 100         if (pstr->offsets[mid] > offset)
599 20           high = mid;
600 11 100         else if (pstr->offsets[mid] < offset)
601 2           low = mid + 1;
602             else
603 9           break;
604             }
605 22 100         while (low < high);
606 11 100         if (pstr->offsets[mid] < offset)
607 2           ++mid;
608 11           pstr->tip_context = re_string_context_at (aTHX_ pstr, mid - 1,
609             eflags);
610             /* This can be quite complicated, so handle specially
611             only the common and easy case where the character with
612             different length representation of lower and upper
613             case is present at or after offset. */
614 20 50         if (pstr->valid_len > offset
615 11 50         && mid == offset && pstr->offsets[mid] == offset)
    100          
616             {
617 9 50         Move (pstr->wcs + offset, pstr->wcs, pstr->valid_len - offset, rpl__wint_t);
618 9           Move (pstr->mbs + offset, pstr->mbs, pstr->valid_len - offset, char);
619 9           pstr->valid_len -= offset;
620 9           pstr->valid_raw_len -= offset;
621 81 100         for (low = 0; low < pstr->valid_len; low++)
622 72           pstr->offsets[low] = pstr->offsets[low + offset] - offset;
623             }
624             else
625             {
626             /* Otherwise, just find out how long the partial multibyte
627             character at offset is and fill it with rpl__WEOF/255. */
628 2           pstr->len = pstr->raw_len - idx + offset;
629 2           pstr->stop = pstr->raw_stop - idx + offset;
630 2           pstr->offsets_needed = 0;
631 2 50         while (mid > 0 && pstr->offsets[mid - 1] == offset)
    50          
632 0           --mid;
633 2 50         while (mid < pstr->valid_len)
634 2 50         if (pstr->wcs[mid] != rpl__WEOF)
635 2           break;
636             else
637 0           ++mid;
638 2 50         if (mid == pstr->valid_len)
639 0           pstr->valid_len = 0;
640             else
641             {
642 2           pstr->valid_len = pstr->offsets[mid] - offset;
643 2 50         if (pstr->valid_len)
644             {
645 4 100         for (low = 0; low < pstr->valid_len; ++low)
646 2           pstr->wcs[low] = rpl__WEOF;
647 2           memset (pstr->mbs, 255, pstr->valid_len);
648             }
649             }
650 11           pstr->valid_raw_len = pstr->valid_len;
651             }
652             }
653             else
654             #endif
655             {
656 24           pstr->tip_context = re_string_context_at (aTHX_ pstr, offset - 1,
657             eflags);
658             #ifdef RE_ENABLE_I18N
659 24 50         if (pstr->mb_cur_max > 1)
660 24 50         Move (pstr->wcs + offset, pstr->wcs, pstr->valid_len - offset, rpl__wint_t);
661             #endif /* RE_ENABLE_I18N */
662 24 100         if (BE (pstr->mbs_allocated, 0))
663 3           Move (pstr->mbs + offset, pstr->mbs, pstr->valid_len - offset, char);
664 24           pstr->valid_len -= offset;
665 35           pstr->valid_raw_len -= offset;
666             #if DEBUG
667             assert (pstr->valid_len > 0);
668             #endif
669             }
670             }
671             else
672             {
673             #ifdef RE_ENABLE_I18N
674             /* No, skip all characters until IDX. */
675 10           Idx prev_valid_len = pstr->valid_len;
676              
677 10 50         if (BE (pstr->offsets_needed, 0))
678             {
679 0           pstr->len = pstr->raw_len - idx + offset;
680 0           pstr->stop = pstr->raw_stop - idx + offset;
681 0           pstr->offsets_needed = 0;
682             }
683             #endif
684 10           pstr->valid_len = 0;
685             #ifdef RE_ENABLE_I18N
686 10 50         if (pstr->mb_cur_max > 1)
687             {
688             Idx wcs_idx;
689 10           rpl__wint_t wc = rpl__WEOF;
690              
691 10 50         if (pstr->is_utf8)
692             {
693             const unsigned char *raw, *p, *end;
694              
695             /* Special case UTF-8. Multi-byte chars start with any
696             byte other than 0x80 - 0xbf. */
697 0           raw = pstr->raw_mbs + pstr->raw_mbs_idx;
698 0           end = raw + (offset - pstr->mb_cur_max);
699 0 0         if (end < pstr->raw_mbs)
700 0           end = pstr->raw_mbs;
701 0           p = raw + offset - 1;
702             #if (defined(_LIBC) || defined(_PERL_I18N))
703             /* For the simple case, ASCII characters, skip the conversion step. */
704 0 0         if (rpl__isascii (*p) && BE (pstr->trans == NULL, 1))
    0          
705             {
706 0           memset (&pstr->cur_state, '\0', sizeof (rpl__mbstate_t));
707             /* pstr->valid_len = 0; */
708 0           wc = (rpl__wchar_t) *p;
709             }
710             else
711             #endif
712 0 0         for (; p >= end; --p)
713 0 0         if ((*p & 0xc0) != 0x80)
714             {
715             rpl__mbstate_t cur_state;
716             rpl__wchar_t wc2;
717 0           Idx mlen = raw + pstr->len - p;
718             unsigned char buf[6];
719             size_t mbclen;
720              
721 0           const unsigned char *pp = p;
722 0 0         if (BE (pstr->trans != NULL, 0))
723             {
724 0           int i = (int)mlen < 6 ? (int)mlen : 6;
725 0 0         while (--i >= 0)
726 0           buf[i] = pstr->trans[p[i]];
727 0           pp = buf;
728             }
729             /* XXX Don't use mbrtowc, we know which conversion
730             to use (UTF-8 -> UCS4). */
731 0           memset (&cur_state, 0, sizeof (cur_state));
732 0           mbclen = rpl__mbrtowc (&wc2, (const char *) pp, mlen,
733             &cur_state);
734 0 0         if (raw + offset - p <= mbclen
735 0 0         && mbclen < (size_t) -2)
736             {
737 0           memset (&pstr->cur_state, '\0',
738             sizeof (rpl__mbstate_t));
739 0           pstr->valid_len = mbclen - (raw + offset - p);
740 0           wc = wc2;
741             }
742 0           break;
743             }
744             }
745              
746 10 50         if (wc == rpl__WEOF)
747 10           pstr->valid_len = re_string_skip_chars (aTHX_ pstr, idx, &wc) - idx;
748 10 100         if (wc == rpl__WEOF)
749             pstr->tip_context
750 2           = re_string_context_at (aTHX_ pstr, prev_valid_len - 1, eflags);
751             else
752 8 50         pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
    50          
753 0 0         && IS_WIDE_WORD_CHAR (wc))
    0          
754             ? CONTEXT_WORD
755 8           : ((IS_WIDE_NEWLINE (wc)
756 0 0         && pstr->newline_anchor)
757             ? CONTEXT_NEWLINE : 0));
758 10 50         if (BE (pstr->valid_len, 0))
759             {
760 0 0         for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
761 0           pstr->wcs[wcs_idx] = rpl__WEOF;
762 0 0         if (pstr->mbs_allocated)
763 0           memset (pstr->mbs, 255, pstr->valid_len);
764             }
765 10           pstr->valid_raw_len = pstr->valid_len;
766             }
767             else
768             #endif /* RE_ENABLE_I18N */
769             {
770 0           int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
771 0           pstr->valid_raw_len = 0;
772 0 0         if (pstr->trans)
773 0           c = pstr->trans[c];
774 0 0         pstr->tip_context = (bitset_contain (aTHX_ pstr->word_char, c)
    0          
775             ? CONTEXT_WORD
776 0 0         : ((IS_NEWLINE (c) && pstr->newline_anchor)
777             ? CONTEXT_NEWLINE : 0));
778             }
779             }
780 45 100         if (!BE (pstr->mbs_allocated, 0))
781 30           pstr->mbs += offset;
782             }
783 51           pstr->raw_mbs_idx = idx;
784 51           pstr->len -= offset;
785 51           pstr->stop -= offset;
786              
787             /* Then build the buffers. */
788             #ifdef RE_ENABLE_I18N
789 51 50         if (pstr->mb_cur_max > 1)
790             {
791 51 100         if (pstr->icase)
792             {
793 16           reg_errcode_t ret = build_wcs_upper_buffer (aTHX_ pstr);
794 16 50         if (BE (ret != REG_NOERROR, 0))
795 16           return ret;
796             }
797             else
798 51           build_wcs_buffer (aTHX_ pstr);
799             }
800             else
801             #endif /* RE_ENABLE_I18N */
802 0 0         if (BE (pstr->mbs_allocated, 0))
803             {
804 0 0         if (pstr->icase)
805 0           build_upper_buffer (aTHX_ pstr);
806 0 0         else if (pstr->trans != NULL)
807 0           re_string_translate_buffer (aTHX_ pstr);
808             }
809             else
810 0           pstr->valid_len = pstr->len;
811              
812 51           pstr->cur_idx = 0;
813 51           return REG_NOERROR;
814             }
815              
816             static unsigned char
817             internal_function __attribute__ ((pure))
818 12           re_string_peek_byte_case (pTHX_ const re_string_t *pstr, Idx idx)
819             {
820             int ch;
821             Idx off;
822              
823             /* Handle the common (easiest) cases first. */
824 12 50         if (BE (!pstr->mbs_allocated, 1))
825 12           return re_string_peek_byte (aTHX_ pstr, idx);
826              
827             #ifdef RE_ENABLE_I18N
828 0 0         if (pstr->mb_cur_max > 1
829 0 0         && ! re_string_is_single_byte_char (aTHX_ pstr, pstr->cur_idx + idx))
    0          
    0          
830 0           return re_string_peek_byte (aTHX_ pstr, idx);
831             #endif
832              
833 0           off = pstr->cur_idx + idx;
834             #ifdef RE_ENABLE_I18N
835 0 0         if (pstr->offsets_needed)
836 0           off = pstr->offsets[off];
837             #endif
838              
839 0           ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
840              
841             #ifdef RE_ENABLE_I18N
842             /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
843             this function returns CAPITAL LETTER I instead of first byte of
844             DOTLESS SMALL LETTER I. The latter would confuse the parser,
845             since peek_byte_case doesn't advance cur_idx in any way. */
846 0 0         if (pstr->offsets_needed && !rpl__isascii (ch))
    0          
847 0           return re_string_peek_byte (aTHX_ pstr, idx);
848             #endif
849              
850 0           return ch;
851             }
852              
853             static unsigned char
854             internal_function
855 0           re_string_fetch_byte_case (pTHX_ re_string_t *pstr)
856             {
857 0 0         if (BE (!pstr->mbs_allocated, 1))
858 0           return re_string_fetch_byte (aTHX_ pstr);
859              
860             #ifdef RE_ENABLE_I18N
861 0 0         if (pstr->offsets_needed)
862             {
863             Idx off;
864             int ch;
865              
866             /* For tr_TR.UTF-8 [[:islower:]] there is
867             [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
868             in that case the whole multi-byte character and return
869             the original letter. On the other side, with
870             [[: DOTLESS SMALL LETTER I return [[:I, as doing
871             anything else would complicate things too much. */
872              
873 0 0         if (!re_string_first_byte (aTHX_ pstr, pstr->cur_idx))
    0          
874 0           return re_string_fetch_byte (aTHX_ pstr);
875              
876 0           off = pstr->offsets[pstr->cur_idx];
877 0           ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
878              
879 0 0         if (! rpl__isascii (ch))
880 0           return re_string_fetch_byte (aTHX_ pstr);
881              
882 0           re_string_skip_bytes (aTHX_ pstr,
883             re_string_char_size_at (aTHX_ pstr, pstr->cur_idx));
884 0           return ch;
885             }
886             #endif
887              
888 0           return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
889             }
890              
891             static void
892             internal_function
893 20           re_string_destruct (pTHX_ re_string_t *pstr)
894             {
895             #ifdef RE_ENABLE_I18N
896 20 50         re_free (pstr->wcs);
897 20 100         re_free (pstr->offsets);
898             #endif /* RE_ENABLE_I18N */
899 20 100         if (pstr->mbs_allocated)
900 2 50         re_free (pstr->mbs);
901 20           }
902              
903             /* Return the context at IDX in INPUT. */
904              
905             static unsigned int
906             internal_function
907 81           re_string_context_at (pTHX_ const re_string_t *input, Idx idx, int eflags)
908             {
909             int c;
910 81 50         if (BE (! REG_VALID_INDEX (idx), 0))
911             /* In this case, we use the value stored in input->tip_context,
912             since we can't know the character in input->mbs[-1] here. */
913 0           return input->tip_context;
914 81 100         if (BE (idx == input->len, 0))
915 3 50         return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
916             : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
917             #ifdef RE_ENABLE_I18N
918 78 50         if (input->mb_cur_max > 1)
919             {
920             rpl__wint_t wc;
921 78           Idx wc_idx = idx;
922 142 100         while(input->wcs[wc_idx] == rpl__WEOF)
923             {
924             #ifdef DEBUG
925             /* It must not happen. */
926             assert (REG_VALID_INDEX (wc_idx));
927             #endif
928 80           --wc_idx;
929 80 100         if (! REG_VALID_INDEX (wc_idx))
930 16           return input->tip_context;
931             }
932 62           wc = input->wcs[wc_idx];
933 62 50         if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
    0          
    0          
934 0           return CONTEXT_WORD;
935 62 50         return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
    0          
936             ? CONTEXT_NEWLINE : 0);
937             }
938             else
939             #endif
940             {
941 0           c = re_string_byte_at (aTHX_ input, idx);
942 0 0         if (bitset_contain (aTHX_ input->word_char, c))
943 0           return CONTEXT_WORD;
944 0 0         return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
    0          
945             }
946             }
947            
948             /* Functions for set operation. */
949              
950             static reg_errcode_t
951             internal_function __attribute_warn_unused_result__
952 100           re_node_set_alloc (pTHX_ re_node_set *set, Idx size)
953             {
954 100           set->alloc = size;
955 100           set->nelem = 0;
956 100 50         re_malloc (set->elems, Idx, size);
957 100           return REG_NOERROR;
958             }
959              
960             static reg_errcode_t
961             internal_function __attribute_warn_unused_result__
962 50           re_node_set_init_1 (pTHX_ re_node_set *set, Idx elem)
963             {
964 50           set->alloc = 1;
965 50           set->nelem = 1;
966 50           re_malloc (set->elems, Idx, 1);
967 50           set->elems[0] = elem;
968 50           return REG_NOERROR;
969             }
970              
971             static reg_errcode_t
972             internal_function __attribute_warn_unused_result__
973 2           re_node_set_init_2 (pTHX_ re_node_set *set, Idx elem1, Idx elem2)
974             {
975 2           set->alloc = 2;
976 2           re_malloc (set->elems, Idx, 2);
977 2 50         if (elem1 == elem2)
978             {
979 0           set->nelem = 1;
980 0           set->elems[0] = elem1;
981             }
982             else
983             {
984 2           set->nelem = 2;
985 2 50         if (elem1 < elem2)
986             {
987 2           set->elems[0] = elem1;
988 2           set->elems[1] = elem2;
989             }
990             else
991             {
992 0           set->elems[0] = elem2;
993 0           set->elems[1] = elem1;
994             }
995             }
996 2           return REG_NOERROR;
997             }
998              
999             static reg_errcode_t
1000             internal_function __attribute_warn_unused_result__
1001 36           re_node_set_init_copy (pTHX_ re_node_set *dest, const re_node_set *src)
1002             {
1003 36           dest->nelem = src->nelem;
1004 36 50         if (src->nelem > 0)
1005             {
1006 36           dest->alloc = dest->nelem;
1007 36 50         re_malloc (dest->elems, Idx, dest->alloc);
1008 36 50         Copy (src->elems, dest->elems, src->nelem, Idx);
1009             }
1010             else
1011 0           re_node_set_init_empty (dest);
1012 36           return REG_NOERROR;
1013             }
1014              
1015             /* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
1016             DEST. Return value indicate the error code or REG_NOERROR if succeeded.
1017             Note: We assume dest->elems is NULL, when dest->alloc is 0. */
1018              
1019             static reg_errcode_t
1020             internal_function __attribute_warn_unused_result__
1021 19           re_node_set_add_intersect (pTHX_ re_node_set *dest, const re_node_set *src1,
1022             const re_node_set *src2)
1023             {
1024             Idx i1, i2, is, id, delta, sbase;
1025 19 50         if (src1->nelem == 0 || src2->nelem == 0)
    50          
1026 0           return REG_NOERROR;
1027              
1028             /* We need dest->nelem + 2 * elems_in_intersection; this is a
1029             conservative estimate. */
1030 19 100         if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
1031             {
1032 18           Idx new_alloc = src1->nelem + src2->nelem + dest->alloc;
1033 18 50         re_realloc (dest->elems, Idx, new_alloc);
1034 18           dest->alloc = new_alloc;
1035             }
1036              
1037             /* Find the items in the intersection of SRC1 and SRC2, and copy
1038             into the top of DEST those that are not already in DEST itself. */
1039 19           sbase = dest->nelem + src1->nelem + src2->nelem;
1040 19           i1 = src1->nelem - 1;
1041 19           i2 = src2->nelem - 1;
1042 19           id = dest->nelem - 1;
1043             for (;;)
1044             {
1045 57 100         if (src1->elems[i1] == src2->elems[i2])
1046             {
1047             /* Try to find the item in DEST. Maybe we could binary search? */
1048 67 100         while (REG_VALID_INDEX (id) && dest->elems[id] > src1->elems[i1])
    100          
1049 19           --id;
1050              
1051 48 100         if (! REG_VALID_INDEX (id) || dest->elems[id] != src1->elems[i1])
    100          
1052 29           dest->elems[--sbase] = src1->elems[i1];
1053              
1054 48 100         if (! REG_VALID_INDEX (--i1) || ! REG_VALID_INDEX (--i2))
    50          
1055             break;
1056             }
1057              
1058             /* Lower the highest of the two items. */
1059 9 50         else if (src1->elems[i1] < src2->elems[i2])
1060             {
1061 0 0         if (! REG_VALID_INDEX (--i2))
1062 0           break;
1063             }
1064             else
1065             {
1066 9 50         if (! REG_VALID_INDEX (--i1))
1067 0           break;
1068             }
1069 38           }
1070              
1071 19           id = dest->nelem - 1;
1072 19           is = dest->nelem + src1->nelem + src2->nelem - 1;
1073 19           delta = is - sbase + 1;
1074              
1075             /* Now copy. When DELTA becomes zero, the remaining
1076             DEST elements are already in place; this is more or
1077             less the same loop that is in re_node_set_merge. */
1078 19           dest->nelem += delta;
1079 19 50         if (delta > 0 && REG_VALID_INDEX (id))
    50          
1080             for (;;)
1081             {
1082 28 100         if (dest->elems[is] > dest->elems[id])
1083             {
1084             /* Copy from the top. */
1085 9           dest->elems[id + delta--] = dest->elems[is--];
1086 9 50         if (delta == 0)
1087 0           break;
1088             }
1089             else
1090             {
1091             /* Slide from the bottom. */
1092 19           dest->elems[id + delta] = dest->elems[id];
1093 19 50         if (! REG_VALID_INDEX (--id))
1094 19           break;
1095             }
1096 9           }
1097              
1098             /* Copy remaining SRC elements. */
1099 19 50         Copy (dest->elems + sbase, dest->elems, delta, Idx);
1100              
1101 19           return REG_NOERROR;
1102             }
1103              
1104             /* Calculate the union set of the sets SRC1 and SRC2. And store it to
1105             DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1106              
1107             static reg_errcode_t
1108             internal_function __attribute_warn_unused_result__
1109 0           re_node_set_init_union (pTHX_ re_node_set *dest, const re_node_set *src1,
1110             const re_node_set *src2)
1111             {
1112             Idx i1, i2, id;
1113 0 0         if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
    0          
    0          
    0          
1114             {
1115 0           dest->alloc = src1->nelem + src2->nelem;
1116 0 0         re_malloc (dest->elems, Idx, dest->alloc);
1117             }
1118             else
1119             {
1120 0 0         if (src1 != NULL && src1->nelem > 0)
    0          
1121 0           return re_node_set_init_copy (aTHX_ dest, src1);
1122 0 0         else if (src2 != NULL && src2->nelem > 0)
    0          
1123 0           return re_node_set_init_copy (aTHX_ dest, src2);
1124             else
1125 0           re_node_set_init_empty (dest);
1126 0           return REG_NOERROR;
1127             }
1128 0 0         for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
    0          
1129             {
1130 0 0         if (src1->elems[i1] > src2->elems[i2])
1131             {
1132 0           dest->elems[id++] = src2->elems[i2++];
1133 0           continue;
1134             }
1135 0 0         if (src1->elems[i1] == src2->elems[i2])
1136 0           ++i2;
1137 0           dest->elems[id++] = src1->elems[i1++];
1138             }
1139 0 0         if (i1 < src1->nelem)
1140             {
1141 0 0         Copy (src1->elems + i1, dest->elems + id, src1->nelem - i1, Idx);
1142 0           id += src1->nelem - i1;
1143             }
1144 0 0         else if (i2 < src2->nelem)
1145             {
1146 0 0         Copy (src2->elems + i2, dest->elems + id, src2->nelem - i2, Idx);
1147 0           id += src2->nelem - i2;
1148             }
1149 0           dest->nelem = id;
1150 0           return REG_NOERROR;
1151             }
1152              
1153             /* Calculate the union set of the sets DEST and SRC. And store it to
1154             DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1155              
1156             static reg_errcode_t
1157             internal_function __attribute_warn_unused_result__
1158 38           re_node_set_merge (pTHX_ re_node_set *dest, const re_node_set *src)
1159             {
1160             Idx is, id, sbase, delta;
1161 38 50         if (src == NULL || src->nelem == 0)
    50          
1162 0           return REG_NOERROR;
1163 38 100         if (dest->alloc < 2 * src->nelem + dest->nelem)
1164             {
1165 14           Idx new_alloc = 2 * (src->nelem + dest->alloc);
1166 14 50         re_realloc (dest->elems, Idx, new_alloc);
1167 14           dest->alloc = new_alloc;
1168             }
1169              
1170 38 100         if (BE (dest->nelem == 0, 0))
1171             {
1172 36           dest->nelem = src->nelem;
1173 36 50         Copy (src->elems, dest->elems, src->nelem, Idx);
1174 36           return REG_NOERROR;
1175             }
1176              
1177             /* Copy into the top of DEST the items of SRC that are not
1178             found in DEST. Maybe we could binary search in DEST? */
1179 4 100         for (sbase = dest->nelem + 2 * src->nelem,
1180 2           is = src->nelem - 1, id = dest->nelem - 1;
1181 2 50         REG_VALID_INDEX (is) && REG_VALID_INDEX (id); )
1182             {
1183 2 50         if (dest->elems[id] == src->elems[is])
1184 0           is--, id--;
1185 2 50         else if (dest->elems[id] < src->elems[is])
1186 2           dest->elems[--sbase] = src->elems[is--];
1187             else /* if (dest->elems[id] > src->elems[is]) */
1188 0           --id;
1189             }
1190              
1191 2 50         if (REG_VALID_INDEX (is))
1192             {
1193             /* If DEST is exhausted, the remaining items of SRC must be unique. */
1194 0           sbase -= is + 1;
1195 0 0         Copy (src->elems, dest->elems + sbase, is + 1, Idx);
1196             }
1197              
1198 2           id = dest->nelem - 1;
1199 2           is = dest->nelem + 2 * src->nelem - 1;
1200 2           delta = is - sbase + 1;
1201 2 50         if (delta == 0)
1202 0           return REG_NOERROR;
1203              
1204             /* Now copy. When DELTA becomes zero, the remaining
1205             DEST elements are already in place. */
1206 2           dest->nelem += delta;
1207             for (;;)
1208             {
1209 2 50         if (dest->elems[is] > dest->elems[id])
1210             {
1211             /* Copy from the top. */
1212 2           dest->elems[id + delta--] = dest->elems[is--];
1213 2 50         if (delta == 0)
1214 2           break;
1215             }
1216             else
1217             {
1218             /* Slide from the bottom. */
1219 0           dest->elems[id + delta] = dest->elems[id];
1220 0 0         if (! REG_VALID_INDEX (--id))
1221             {
1222             /* Copy remaining SRC elements. */
1223 0 0         Copy (dest->elems + sbase, dest->elems, delta, Idx);
1224 0           break;
1225             }
1226             }
1227 0           }
1228              
1229 2           return REG_NOERROR;
1230             }
1231              
1232             /* Insert the new element ELEM to the re_node_set* SET.
1233             SET should not already have ELEM.
1234             Return true if successful. */
1235              
1236             static bool
1237             internal_function __attribute_warn_unused_result__
1238 93           re_node_set_insert (pTHX_ re_node_set *set, Idx elem)
1239             {
1240             Idx idx;
1241             /* In case the set is empty. */
1242 93 100         if (set->alloc == 0)
1243 12           return BE (re_node_set_init_1 (aTHX_ set, elem) == REG_NOERROR, 1);
1244              
1245 81 100         if (BE (set->nelem, 0) == 0)
1246             {
1247             /* We already guaranteed above that set->alloc != 0. */
1248 57           set->elems[0] = elem;
1249 57           ++set->nelem;
1250 57           return true;
1251             }
1252              
1253             /* Realloc if we need. */
1254 24 100         if (set->alloc == set->nelem)
1255             {
1256 9           set->alloc = set->alloc * 2;
1257 9 50         re_realloc (set->elems, Idx, set->alloc);
1258             }
1259              
1260             /* Move the elements which follows the new element. Test the
1261             first element separately to skip a check in the inner loop. */
1262 24 100         if (elem < set->elems[0])
1263             {
1264 12           idx = 0;
1265 29 100         for (idx = set->nelem; idx > 0; idx--)
1266 17           set->elems[idx] = set->elems[idx - 1];
1267             }
1268             else
1269             {
1270 12 50         for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
1271 0           set->elems[idx] = set->elems[idx - 1];
1272             }
1273              
1274             /* Insert the new element. */
1275 24           set->elems[idx] = elem;
1276 24           ++set->nelem;
1277 24           return true;
1278             }
1279              
1280             /* Insert the new element ELEM to the re_node_set* SET.
1281             SET should not already have any element greater than or equal to ELEM.
1282             Return true if successful. */
1283              
1284             static bool
1285             internal_function __attribute_warn_unused_result__
1286 62           re_node_set_insert_last (pTHX_ re_node_set *set, Idx elem)
1287             {
1288             /* Realloc if we need. */
1289 62 100         if (set->alloc == set->nelem)
1290             {
1291 20           set->alloc = (set->alloc + 1) * 2;
1292 20 50         re_realloc (set->elems, Idx, set->alloc);
1293             }
1294              
1295             /* Insert the new element. */
1296 62           set->elems[set->nelem++] = elem;
1297 62           return true;
1298             }
1299              
1300             /* Compare two node sets SET1 and SET2.
1301             Return true if SET1 and SET2 are equivalent. */
1302              
1303             static bool
1304             internal_function __attribute__ ((pure))
1305 66           re_node_set_compare (pTHX_ const re_node_set *set1, const re_node_set *set2)
1306             {
1307             Idx i;
1308 66 50         if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
    50          
    100          
1309 3           return false;
1310 199 100         for (i = set1->nelem ; REG_VALID_INDEX (--i) ; )
1311 136 50         if (set1->elems[i] != set2->elems[i])
1312 0           return false;
1313 63           return true;
1314             }
1315              
1316             /* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
1317              
1318             static Idx
1319             internal_function __attribute__ ((pure))
1320 54           re_node_set_contains (pTHX_ const re_node_set *set, Idx elem)
1321             {
1322             __re_size_t idx, right, mid;
1323 54 50         if (! REG_VALID_NONZERO_INDEX (set->nelem))
1324 0           return 0;
1325              
1326             /* Binary search the element. */
1327 54           idx = 0;
1328 54           right = set->nelem - 1;
1329 128 100         while (idx < right)
1330             {
1331 74           mid = (idx + right) / 2;
1332 74 100         if (set->elems[mid] < elem)
1333 44           idx = mid + 1;
1334             else
1335 30           right = mid;
1336             }
1337 54 100         return set->elems[idx] == elem ? idx + 1 : 0;
1338             }
1339              
1340             static void
1341             internal_function
1342 0           re_node_set_remove_at (pTHX_ re_node_set *set, Idx idx)
1343             {
1344 0 0         if (idx < 0 || idx >= set->nelem)
1345 0           return;
1346 0           --set->nelem;
1347 0 0         for (; idx < set->nelem; idx++)
1348 0           set->elems[idx] = set->elems[idx + 1];
1349             }
1350            
1351              
1352             /* Add the token TOKEN to dfa->nodes, and return the index of the token.
1353             Or return REG_MISSING if an error occurred. */
1354              
1355             static Idx
1356             internal_function
1357 48           re_dfa_add_node (pTHX_ re_dfa_t *dfa, re_token_t token)
1358             {
1359 48 50         if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
1360             {
1361 0           size_t new_nodes_alloc = dfa->nodes_alloc * 2;
1362              
1363             /* Avoid overflows in realloc. */
1364 0           const size_t max_object_size = MAX (sizeof (re_token_t),
1365             MAX (sizeof (re_node_set),
1366             sizeof (Idx)));
1367 0 0         if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_nodes_alloc, 0))
1368 0           return REG_MISSING;
1369              
1370 0 0         re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
1371 0 0         re_realloc (dfa->nexts, Idx, new_nodes_alloc);
1372 0 0         re_realloc (dfa->org_indices, Idx, new_nodes_alloc);
1373 0 0         re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
1374 0 0         re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
1375 0           dfa->nodes_alloc = new_nodes_alloc;
1376             }
1377 48           dfa->nodes[dfa->nodes_len] = token;
1378 48           dfa->nodes[dfa->nodes_len].constraint = 0;
1379             #ifdef RE_ENABLE_I18N
1380 96           dfa->nodes[dfa->nodes_len].accept_mb =
1381 0 0         ((token.type == OP_PERIOD && dfa->mb_cur_max > 1)
1382 48 50         || token.type == COMPLEX_BRACKET);
    100          
1383             #endif
1384 48           dfa->nexts[dfa->nodes_len] = REG_MISSING;
1385 48           re_node_set_init_empty (dfa->edests + dfa->nodes_len);
1386 48           re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
1387 48           return dfa->nodes_len++;
1388             }
1389              
1390             static re_hashval_t
1391             internal_function
1392 93           calc_state_hash (pTHX_ const re_node_set *nodes, unsigned int context)
1393             {
1394 93           re_hashval_t hash = nodes->nelem + context;
1395             Idx i;
1396 279 100         for (i = 0 ; i < nodes->nelem ; i++)
1397 186           hash += nodes->elems[i];
1398 93           return hash;
1399             }
1400              
1401             /* Search for the state whose node_set is equivalent to NODES.
1402             Return the pointer to the state, if we found it in the DFA.
1403             Otherwise create the new one and return it. In case of an error
1404             return NULL and set the error code in ERR.
1405             Note: - We assume NULL as the invalid state, then it is possible that
1406             return value is NULL and ERR is REG_NOERROR.
1407             - We never return non-NULL value in case of any errors, it is for
1408             optimization. */
1409              
1410             static re_dfastate_t *
1411             internal_function __attribute_warn_unused_result__
1412 38           re_acquire_state (pTHX_ reg_errcode_t *err, const re_dfa_t *dfa,
1413             const re_node_set *nodes)
1414             {
1415             re_hashval_t hash;
1416             re_dfastate_t *new_state;
1417             struct re_state_table_entry *spot;
1418             Idx i;
1419             #ifdef lint
1420             /* Suppress bogus uninitialized-variable warnings. */
1421             *err = REG_NOERROR;
1422             #endif
1423 38 50         if (BE (nodes->nelem == 0, 0))
1424             {
1425 0           *err = REG_NOERROR;
1426 0           return NULL;
1427             }
1428 38           hash = calc_state_hash (aTHX_ nodes, 0);
1429 38           spot = dfa->state_table + (hash & dfa->state_hash_mask);
1430              
1431 38 100         for (i = 0 ; i < spot->num ; i++)
1432             {
1433 31           re_dfastate_t *state = spot->array[i];
1434 31 50         if (hash != state->hash)
1435 0           continue;
1436 31 50         if (re_node_set_compare (aTHX_ &state->nodes, nodes))
1437 31           return state;
1438             }
1439              
1440             /* There are no appropriate state in the dfa, create the new one. */
1441 7           new_state = create_ci_newstate (aTHX_ dfa, nodes, hash);
1442 7 50         if (BE (new_state == NULL, 0))
1443 0           *err = REG_ESPACE;
1444              
1445 7           return new_state;
1446             }
1447              
1448             /* Search for the state whose node_set is equivalent to NODES and
1449             whose context is equivalent to CONTEXT.
1450             Return the pointer to the state, if we found it in the DFA.
1451             Otherwise create the new one and return it. In case of an error
1452             return NULL and set the error code in ERR.
1453             Note: - We assume NULL as the invalid state, then it is possible that
1454             return value is NULL and ERR is REG_NOERROR.
1455             - We never return non-NULL value in case of any errors, it is for
1456             optimization. */
1457              
1458             static re_dfastate_t *
1459             internal_function __attribute_warn_unused_result__
1460 55           re_acquire_state_context (pTHX_ reg_errcode_t *err, const re_dfa_t *dfa,
1461             const re_node_set *nodes, unsigned int context)
1462             {
1463             re_hashval_t hash;
1464             re_dfastate_t *new_state;
1465             struct re_state_table_entry *spot;
1466             Idx i;
1467             #ifdef lint
1468             /* Suppress bogus uninitialized-variable warnings. */
1469             *err = REG_NOERROR;
1470             #endif
1471 55 50         if (nodes->nelem == 0)
1472             {
1473 0           *err = REG_NOERROR;
1474 0           return NULL;
1475             }
1476 55           hash = calc_state_hash (aTHX_ nodes, context);
1477 55           spot = dfa->state_table + (hash & dfa->state_hash_mask);
1478              
1479 58 100         for (i = 0 ; i < spot->num ; i++)
1480             {
1481 35           re_dfastate_t *state = spot->array[i];
1482 35 50         if (state->hash == hash
1483 35 50         && state->context == context
1484 35 100         && re_node_set_compare (aTHX_ state->entrance_nodes, nodes))
1485 32           return state;
1486             }
1487             /* There are no appropriate state in 'dfa', create the new one. */
1488 23           new_state = create_cd_newstate (aTHX_ dfa, nodes, context, hash);
1489 23 50         if (BE (new_state == NULL, 0))
1490 0           *err = REG_ESPACE;
1491              
1492 23           return new_state;
1493             }
1494              
1495             /* Finish initialization of the new state NEWSTATE, and using its hash value
1496             HASH put in the appropriate bucket of DFA's state table. Return value
1497             indicates the error code if failed. */
1498              
1499             static reg_errcode_t
1500             __attribute_warn_unused_result__
1501 30           register_state (pTHX_ const re_dfa_t *dfa, re_dfastate_t *newstate,
1502             re_hashval_t hash)
1503             {
1504             struct re_state_table_entry *spot;
1505             reg_errcode_t err;
1506             Idx i;
1507              
1508 30           newstate->hash = hash;
1509 30           err = re_node_set_alloc (aTHX_ &newstate->non_eps_nodes, newstate->nodes.nelem);
1510 30 50         if (BE (err != REG_NOERROR, 0))
1511 0           return REG_ESPACE;
1512 80 100         for (i = 0; i < newstate->nodes.nelem; i++)
1513             {
1514 50           Idx elem = newstate->nodes.elems[i];
1515 50 100         if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
1516 32 50         if (! re_node_set_insert_last (aTHX_ &newstate->non_eps_nodes, elem))
1517 0           return REG_ESPACE;
1518             }
1519              
1520 30           spot = dfa->state_table + (hash & dfa->state_hash_mask);
1521 30 100         if (BE (spot->alloc <= spot->num, 0))
1522             {
1523 27           Idx new_alloc = 2 * spot->num + 2;
1524 27 50         re_realloc (spot->array, re_dfastate_t *, new_alloc);
1525 27           spot->alloc = new_alloc;
1526             }
1527 30           spot->array[spot->num++] = newstate;
1528 30           return REG_NOERROR;
1529             }
1530              
1531             static void
1532 30           free_state (pTHX_ re_dfastate_t *state)
1533             {
1534 30 50         re_node_set_free (&state->non_eps_nodes);
1535 30 100         re_node_set_free (&state->inveclosure);
1536 30 50         if (state->entrance_nodes != &state->nodes)
1537             {
1538 0 0         re_node_set_free (state->entrance_nodes);
1539 0 0         re_free (state->entrance_nodes);
1540             }
1541 30 50         re_node_set_free (&state->nodes);
1542 30 50         re_free (state->word_trtable);
1543 30 100         re_free (state->trtable);
1544 30 50         re_free (state);
1545 30           }
1546              
1547             /* Create the new state which is independent of contexts.
1548             Return the new state if succeeded, otherwise return NULL. */
1549              
1550             static re_dfastate_t *
1551             internal_function __attribute_warn_unused_result__
1552 7           create_ci_newstate (pTHX_ const re_dfa_t *dfa, const re_node_set *nodes,
1553             re_hashval_t hash)
1554             {
1555             Idx i;
1556             reg_errcode_t err;
1557             re_dfastate_t *newstate;
1558              
1559 7           re_calloc(newstate, re_dfastate_t, 1);
1560             /* newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); */
1561 7 50         if (BE (newstate == NULL, 0))
1562 0           return NULL;
1563 7           err = re_node_set_init_copy (aTHX_ &newstate->nodes, nodes);
1564 7 50         if (BE (err != REG_NOERROR, 0))
1565             {
1566 0 0         re_free (newstate);
1567 0           return NULL;
1568             }
1569              
1570 7           newstate->entrance_nodes = &newstate->nodes;
1571 18 100         for (i = 0 ; i < nodes->nelem ; i++)
1572             {
1573 11           re_token_t *node = dfa->nodes + nodes->elems[i];
1574 11           re_token_type_t type = node->type;
1575 11 100         if (type == CHARACTER && !node->constraint)
    50          
1576 1           continue;
1577             #ifdef RE_ENABLE_I18N
1578 10           newstate->accept_mb |= node->accept_mb;
1579             #endif /* RE_ENABLE_I18N */
1580              
1581             /* If the state has the halt node, the state is a halt state. */
1582 10 100         if (type == END_OF_RE)
1583 2           newstate->halt = 1;
1584 8 50         else if (type == OP_BACK_REF)
1585 0           newstate->has_backref = 1;
1586 8 50         else if (type == ANCHOR || node->constraint)
    50          
1587 0           newstate->has_constraint = 1;
1588             }
1589 7           err = register_state (aTHX_ dfa, newstate, hash);
1590 7 50         if (BE (err != REG_NOERROR, 0))
1591             {
1592 0           free_state (aTHX_ newstate);
1593 0           newstate = NULL;
1594             }
1595 7           return newstate;
1596             }
1597              
1598             /* Create the new state which is depend on the context CONTEXT.
1599             Return the new state if succeeded, otherwise return NULL. */
1600              
1601             static re_dfastate_t *
1602             internal_function __attribute_warn_unused_result__
1603 23           create_cd_newstate (pTHX_ const re_dfa_t *dfa, const re_node_set *nodes,
1604             unsigned int context, re_hashval_t hash)
1605             {
1606 23           Idx i, nctx_nodes = 0;
1607             reg_errcode_t err;
1608             re_dfastate_t *newstate;
1609              
1610 23           re_calloc(newstate, re_dfastate_t, 1);
1611             /* newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); */
1612 23 50         if (BE (newstate == NULL, 0))
1613 0           return NULL;
1614 23           err = re_node_set_init_copy (aTHX_ &newstate->nodes, nodes);
1615 23 50         if (BE (err != REG_NOERROR, 0))
1616             {
1617 0 0         re_free (newstate);
1618 0           return NULL;
1619             }
1620              
1621 23           newstate->context = context;
1622 23           newstate->entrance_nodes = &newstate->nodes;
1623              
1624 62 100         for (i = 0 ; i < nodes->nelem ; i++)
1625             {
1626 39           re_token_t *node = dfa->nodes + nodes->elems[i];
1627 39           re_token_type_t type = node->type;
1628 39           unsigned int constraint = node->constraint;
1629              
1630 39 100         if (type == CHARACTER && !constraint)
    50          
1631 16           continue;
1632             #ifdef RE_ENABLE_I18N
1633 23           newstate->accept_mb |= node->accept_mb;
1634             #endif /* RE_ENABLE_I18N */
1635              
1636             /* If the state has the halt node, the state is a halt state. */
1637 23 100         if (type == END_OF_RE)
1638 5           newstate->halt = 1;
1639 18 50         else if (type == OP_BACK_REF)
1640 0           newstate->has_backref = 1;
1641              
1642 23 50         if (constraint)
1643             {
1644 0 0         if (newstate->entrance_nodes == &newstate->nodes)
1645             {
1646 0           re_malloc (newstate->entrance_nodes, re_node_set, 1);
1647 0 0         if (re_node_set_init_copy (aTHX_ newstate->entrance_nodes, nodes)
1648             != REG_NOERROR)
1649 0           return NULL;
1650 0           nctx_nodes = 0;
1651 0           newstate->has_constraint = 1;
1652             }
1653              
1654 0 0         if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1655             {
1656 0           re_node_set_remove_at (aTHX_ &newstate->nodes, i - nctx_nodes);
1657 0           ++nctx_nodes;
1658             }
1659             }
1660             }
1661 23           err = register_state (aTHX_ dfa, newstate, hash);
1662 23 50         if (BE (err != REG_NOERROR, 0))
1663             {
1664 0           free_state (aTHX_ newstate);
1665 0           newstate = NULL;
1666             }
1667 23           return newstate;
1668             }