Code

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