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