]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/bits/regex.tcc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / bits / regex.tcc
1 // class template regex -*- C++ -*-
2
3 // Copyright (C) 2013-2019 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This 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
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /**
26 * @file bits/regex.tcc
27 * This is an internal header file, included by other library headers.
28 * Do not attempt to use it directly. @headername{regex}
29 */
30
31 namespace std _GLIBCXX_VISIBILITY(default)
32 {
33 _GLIBCXX_BEGIN_NAMESPACE_VERSION
34
35 namespace __detail
36 {
37 // Result of merging regex_match and regex_search.
38 //
39 // __policy now can be _S_auto (auto dispatch) and _S_alternate (use
40 // the other one if possible, for test purpose).
41 //
42 // That __match_mode is true means regex_match, else regex_search.
43 template<typename _BiIter, typename _Alloc,
44 typename _CharT, typename _TraitsT,
45 _RegexExecutorPolicy __policy,
46 bool __match_mode>
47 bool
48 __regex_algo_impl(_BiIter __s,
49 _BiIter __e,
50 match_results<_BiIter, _Alloc>& __m,
51 const basic_regex<_CharT, _TraitsT>& __re,
52 regex_constants::match_flag_type __flags)
53 {
54 if (__re._M_automaton == nullptr)
55 return false;
56
57 typename match_results<_BiIter, _Alloc>::_Base_type& __res = __m;
58 __m._M_begin = __s;
59 __m._M_resize(__re._M_automaton->_M_sub_count());
60 for (auto& __it : __res)
61 __it.matched = false;
62
63 bool __ret;
64 if ((__re.flags() & regex_constants::__polynomial)
65 || (__policy == _RegexExecutorPolicy::_S_alternate
66 && !__re._M_automaton->_M_has_backref))
67 {
68 _Executor<_BiIter, _Alloc, _TraitsT, false>
69 __executor(__s, __e, __m, __re, __flags);
70 if (__match_mode)
71 __ret = __executor._M_match();
72 else
73 __ret = __executor._M_search();
74 }
75 else
76 {
77 _Executor<_BiIter, _Alloc, _TraitsT, true>
78 __executor(__s, __e, __m, __re, __flags);
79 if (__match_mode)
80 __ret = __executor._M_match();
81 else
82 __ret = __executor._M_search();
83 }
84 if (__ret)
85 {
86 for (auto& __it : __res)
87 if (!__it.matched)
88 __it.first = __it.second = __e;
89 auto& __pre = __m._M_prefix();
90 auto& __suf = __m._M_suffix();
91 if (__match_mode)
92 {
93 __pre.matched = false;
94 __pre.first = __s;
95 __pre.second = __s;
96 __suf.matched = false;
97 __suf.first = __e;
98 __suf.second = __e;
99 }
100 else
101 {
102 __pre.first = __s;
103 __pre.second = __res[0].first;
104 __pre.matched = (__pre.first != __pre.second);
105 __suf.first = __res[0].second;
106 __suf.second = __e;
107 __suf.matched = (__suf.first != __suf.second);
108 }
109 }
110 else
111 {
112 __m._M_resize(0);
113 for (auto& __it : __res)
114 {
115 __it.matched = false;
116 __it.first = __it.second = __e;
117 }
118 }
119 return __ret;
120 }
121 }
122
123 template<typename _Ch_type>
124 template<typename _Fwd_iter>
125 typename regex_traits<_Ch_type>::string_type
126 regex_traits<_Ch_type>::
127 lookup_collatename(_Fwd_iter __first, _Fwd_iter __last) const
128 {
129 typedef std::ctype<char_type> __ctype_type;
130 const __ctype_type& __fctyp(use_facet<__ctype_type>(_M_locale));
131
132 static const char* __collatenames[] =
133 {
134 "NUL",
135 "SOH",
136 "STX",
137 "ETX",
138 "EOT",
139 "ENQ",
140 "ACK",
141 "alert",
142 "backspace",
143 "tab",
144 "newline",
145 "vertical-tab",
146 "form-feed",
147 "carriage-return",
148 "SO",
149 "SI",
150 "DLE",
151 "DC1",
152 "DC2",
153 "DC3",
154 "DC4",
155 "NAK",
156 "SYN",
157 "ETB",
158 "CAN",
159 "EM",
160 "SUB",
161 "ESC",
162 "IS4",
163 "IS3",
164 "IS2",
165 "IS1",
166 "space",
167 "exclamation-mark",
168 "quotation-mark",
169 "number-sign",
170 "dollar-sign",
171 "percent-sign",
172 "ampersand",
173 "apostrophe",
174 "left-parenthesis",
175 "right-parenthesis",
176 "asterisk",
177 "plus-sign",
178 "comma",
179 "hyphen",
180 "period",
181 "slash",
182 "zero",
183 "one",
184 "two",
185 "three",
186 "four",
187 "five",
188 "six",
189 "seven",
190 "eight",
191 "nine",
192 "colon",
193 "semicolon",
194 "less-than-sign",
195 "equals-sign",
196 "greater-than-sign",
197 "question-mark",
198 "commercial-at",
199 "A",
200 "B",
201 "C",
202 "D",
203 "E",
204 "F",
205 "G",
206 "H",
207 "I",
208 "J",
209 "K",
210 "L",
211 "M",
212 "N",
213 "O",
214 "P",
215 "Q",
216 "R",
217 "S",
218 "T",
219 "U",
220 "V",
221 "W",
222 "X",
223 "Y",
224 "Z",
225 "left-square-bracket",
226 "backslash",
227 "right-square-bracket",
228 "circumflex",
229 "underscore",
230 "grave-accent",
231 "a",
232 "b",
233 "c",
234 "d",
235 "e",
236 "f",
237 "g",
238 "h",
239 "i",
240 "j",
241 "k",
242 "l",
243 "m",
244 "n",
245 "o",
246 "p",
247 "q",
248 "r",
249 "s",
250 "t",
251 "u",
252 "v",
253 "w",
254 "x",
255 "y",
256 "z",
257 "left-curly-bracket",
258 "vertical-line",
259 "right-curly-bracket",
260 "tilde",
261 "DEL",
262 };
263
264 string __s;
265 for (; __first != __last; ++__first)
266 __s += __fctyp.narrow(*__first, 0);
267
268 for (const auto& __it : __collatenames)
269 if (__s == __it)
270 return string_type(1, __fctyp.widen(
271 static_cast<char>(&__it - __collatenames)));
272
273 // TODO Add digraph support:
274 // http://boost.sourceforge.net/libs/regex/doc/collating_names.html
275
276 return string_type();
277 }
278
279 template<typename _Ch_type>
280 template<typename _Fwd_iter>
281 typename regex_traits<_Ch_type>::char_class_type
282 regex_traits<_Ch_type>::
283 lookup_classname(_Fwd_iter __first, _Fwd_iter __last, bool __icase) const
284 {
285 typedef std::ctype<char_type> __ctype_type;
286 const __ctype_type& __fctyp(use_facet<__ctype_type>(_M_locale));
287
288 // Mappings from class name to class mask.
289 static const pair<const char*, char_class_type> __classnames[] =
290 {
291 {"d", ctype_base::digit},
292 {"w", {ctype_base::alnum, _RegexMask::_S_under}},
293 {"s", ctype_base::space},
294 {"alnum", ctype_base::alnum},
295 {"alpha", ctype_base::alpha},
296 {"blank", ctype_base::blank},
297 {"cntrl", ctype_base::cntrl},
298 {"digit", ctype_base::digit},
299 {"graph", ctype_base::graph},
300 {"lower", ctype_base::lower},
301 {"print", ctype_base::print},
302 {"punct", ctype_base::punct},
303 {"space", ctype_base::space},
304 {"upper", ctype_base::upper},
305 {"xdigit", ctype_base::xdigit},
306 };
307
308 string __s;
309 for (; __first != __last; ++__first)
310 __s += __fctyp.narrow(__fctyp.tolower(*__first), 0);
311
312 for (const auto& __it : __classnames)
313 if (__s == __it.first)
314 {
315 if (__icase
316 && ((__it.second
317 & (ctype_base::lower | ctype_base::upper)) != 0))
318 return ctype_base::alpha;
319 return __it.second;
320 }
321 return 0;
322 }
323
324 template<typename _Ch_type>
325 bool
326 regex_traits<_Ch_type>::
327 isctype(_Ch_type __c, char_class_type __f) const
328 {
329 typedef std::ctype<char_type> __ctype_type;
330 const __ctype_type& __fctyp(use_facet<__ctype_type>(_M_locale));
331
332 return __fctyp.is(__f._M_base, __c)
333 // [[:w:]]
334 || ((__f._M_extended & _RegexMask::_S_under)
335 && __c == __fctyp.widen('_'));
336 }
337
338 template<typename _Ch_type>
339 int
340 regex_traits<_Ch_type>::
341 value(_Ch_type __ch, int __radix) const
342 {
343 std::basic_istringstream<char_type> __is(string_type(1, __ch));
344 long __v;
345 if (__radix == 8)
346 __is >> std::oct;
347 else if (__radix == 16)
348 __is >> std::hex;
349 __is >> __v;
350 return __is.fail() ? -1 : __v;
351 }
352
353 template<typename _Bi_iter, typename _Alloc>
354 template<typename _Out_iter>
355 _Out_iter match_results<_Bi_iter, _Alloc>::
356 format(_Out_iter __out,
357 const match_results<_Bi_iter, _Alloc>::char_type* __fmt_first,
358 const match_results<_Bi_iter, _Alloc>::char_type* __fmt_last,
359 match_flag_type __flags) const
360 {
361 __glibcxx_assert( ready() );
362 regex_traits<char_type> __traits;
363 typedef std::ctype<char_type> __ctype_type;
364 const __ctype_type&
365 __fctyp(use_facet<__ctype_type>(__traits.getloc()));
366
367 auto __output = [&](size_t __idx)
368 {
369 auto& __sub = (*this)[__idx];
370 if (__sub.matched)
371 __out = std::copy(__sub.first, __sub.second, __out);
372 };
373
374 if (__flags & regex_constants::format_sed)
375 {
376 bool __escaping = false;
377 for (; __fmt_first != __fmt_last; __fmt_first++)
378 {
379 if (__escaping)
380 {
381 __escaping = false;
382 if (__fctyp.is(__ctype_type::digit, *__fmt_first))
383 __output(__traits.value(*__fmt_first, 10));
384 else
385 *__out++ = *__fmt_first;
386 continue;
387 }
388 if (*__fmt_first == '\\')
389 {
390 __escaping = true;
391 continue;
392 }
393 if (*__fmt_first == '&')
394 {
395 __output(0);
396 continue;
397 }
398 *__out++ = *__fmt_first;
399 }
400 if (__escaping)
401 *__out++ = '\\';
402 }
403 else
404 {
405 while (1)
406 {
407 auto __next = std::find(__fmt_first, __fmt_last, '$');
408 if (__next == __fmt_last)
409 break;
410
411 __out = std::copy(__fmt_first, __next, __out);
412
413 auto __eat = [&](char __ch) -> bool
414 {
415 if (*__next == __ch)
416 {
417 ++__next;
418 return true;
419 }
420 return false;
421 };
422
423 if (++__next == __fmt_last)
424 *__out++ = '$';
425 else if (__eat('$'))
426 *__out++ = '$';
427 else if (__eat('&'))
428 __output(0);
429 else if (__eat('`'))
430 {
431 auto& __sub = _M_prefix();
432 if (__sub.matched)
433 __out = std::copy(__sub.first, __sub.second, __out);
434 }
435 else if (__eat('\''))
436 {
437 auto& __sub = _M_suffix();
438 if (__sub.matched)
439 __out = std::copy(__sub.first, __sub.second, __out);
440 }
441 else if (__fctyp.is(__ctype_type::digit, *__next))
442 {
443 long __num = __traits.value(*__next, 10);
444 if (++__next != __fmt_last
445 && __fctyp.is(__ctype_type::digit, *__next))
446 {
447 __num *= 10;
448 __num += __traits.value(*__next++, 10);
449 }
450 if (0 <= __num && __num < this->size())
451 __output(__num);
452 }
453 else
454 *__out++ = '$';
455 __fmt_first = __next;
456 }
457 __out = std::copy(__fmt_first, __fmt_last, __out);
458 }
459 return __out;
460 }
461
462 template<typename _Out_iter, typename _Bi_iter,
463 typename _Rx_traits, typename _Ch_type>
464 _Out_iter
465 regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
466 const basic_regex<_Ch_type, _Rx_traits>& __e,
467 const _Ch_type* __fmt,
468 regex_constants::match_flag_type __flags)
469 {
470 typedef regex_iterator<_Bi_iter, _Ch_type, _Rx_traits> _IterT;
471 _IterT __i(__first, __last, __e, __flags);
472 _IterT __end;
473 if (__i == __end)
474 {
475 if (!(__flags & regex_constants::format_no_copy))
476 __out = std::copy(__first, __last, __out);
477 }
478 else
479 {
480 sub_match<_Bi_iter> __last;
481 auto __len = char_traits<_Ch_type>::length(__fmt);
482 for (; __i != __end; ++__i)
483 {
484 if (!(__flags & regex_constants::format_no_copy))
485 __out = std::copy(__i->prefix().first, __i->prefix().second,
486 __out);
487 __out = __i->format(__out, __fmt, __fmt + __len, __flags);
488 __last = __i->suffix();
489 if (__flags & regex_constants::format_first_only)
490 break;
491 }
492 if (!(__flags & regex_constants::format_no_copy))
493 __out = std::copy(__last.first, __last.second, __out);
494 }
495 return __out;
496 }
497
498 template<typename _Bi_iter,
499 typename _Ch_type,
500 typename _Rx_traits>
501 bool
502 regex_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
503 operator==(const regex_iterator& __rhs) const noexcept
504 {
505 if (_M_pregex == nullptr && __rhs._M_pregex == nullptr)
506 return true;
507 return _M_pregex == __rhs._M_pregex
508 && _M_begin == __rhs._M_begin
509 && _M_end == __rhs._M_end
510 && _M_flags == __rhs._M_flags
511 && _M_match[0] == __rhs._M_match[0];
512 }
513
514 template<typename _Bi_iter,
515 typename _Ch_type,
516 typename _Rx_traits>
517 regex_iterator<_Bi_iter, _Ch_type, _Rx_traits>&
518 regex_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
519 operator++()
520 {
521 // In all cases in which the call to regex_search returns true,
522 // match.prefix().first shall be equal to the previous value of
523 // match[0].second, and for each index i in the half-open range
524 // [0, match.size()) for which match[i].matched is true,
525 // match[i].position() shall return distance(begin, match[i].first).
526 // [28.12.1.4.5]
527 if (_M_match[0].matched)
528 {
529 auto __start = _M_match[0].second;
530 auto __prefix_first = _M_match[0].second;
531 if (_M_match[0].first == _M_match[0].second)
532 {
533 if (__start == _M_end)
534 {
535 _M_pregex = nullptr;
536 return *this;
537 }
538 else
539 {
540 if (regex_search(__start, _M_end, _M_match, *_M_pregex,
541 _M_flags
542 | regex_constants::match_not_null
543 | regex_constants::match_continuous))
544 {
545 __glibcxx_assert(_M_match[0].matched);
546 auto& __prefix = _M_match._M_prefix();
547 __prefix.first = __prefix_first;
548 __prefix.matched = __prefix.first != __prefix.second;
549 // [28.12.1.4.5]
550 _M_match._M_begin = _M_begin;
551 return *this;
552 }
553 else
554 ++__start;
555 }
556 }
557 _M_flags |= regex_constants::match_prev_avail;
558 if (regex_search(__start, _M_end, _M_match, *_M_pregex, _M_flags))
559 {
560 __glibcxx_assert(_M_match[0].matched);
561 auto& __prefix = _M_match._M_prefix();
562 __prefix.first = __prefix_first;
563 __prefix.matched = __prefix.first != __prefix.second;
564 // [28.12.1.4.5]
565 _M_match._M_begin = _M_begin;
566 }
567 else
568 _M_pregex = nullptr;
569 }
570 return *this;
571 }
572
573 template<typename _Bi_iter,
574 typename _Ch_type,
575 typename _Rx_traits>
576 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>&
577 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
578 operator=(const regex_token_iterator& __rhs)
579 {
580 _M_position = __rhs._M_position;
581 _M_subs = __rhs._M_subs;
582 _M_n = __rhs._M_n;
583 _M_suffix = __rhs._M_suffix;
584 _M_has_m1 = __rhs._M_has_m1;
585 _M_normalize_result();
586 return *this;
587 }
588
589 template<typename _Bi_iter,
590 typename _Ch_type,
591 typename _Rx_traits>
592 bool
593 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
594 operator==(const regex_token_iterator& __rhs) const
595 {
596 if (_M_end_of_seq() && __rhs._M_end_of_seq())
597 return true;
598 if (_M_suffix.matched && __rhs._M_suffix.matched
599 && _M_suffix == __rhs._M_suffix)
600 return true;
601 if (_M_end_of_seq() || _M_suffix.matched
602 || __rhs._M_end_of_seq() || __rhs._M_suffix.matched)
603 return false;
604 return _M_position == __rhs._M_position
605 && _M_n == __rhs._M_n
606 && _M_subs == __rhs._M_subs;
607 }
608
609 template<typename _Bi_iter,
610 typename _Ch_type,
611 typename _Rx_traits>
612 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>&
613 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
614 operator++()
615 {
616 _Position __prev = _M_position;
617 if (_M_suffix.matched)
618 *this = regex_token_iterator();
619 else if (_M_n + 1 < _M_subs.size())
620 {
621 _M_n++;
622 _M_result = &_M_current_match();
623 }
624 else
625 {
626 _M_n = 0;
627 ++_M_position;
628 if (_M_position != _Position())
629 _M_result = &_M_current_match();
630 else if (_M_has_m1 && __prev->suffix().length() != 0)
631 {
632 _M_suffix.matched = true;
633 _M_suffix.first = __prev->suffix().first;
634 _M_suffix.second = __prev->suffix().second;
635 _M_result = &_M_suffix;
636 }
637 else
638 *this = regex_token_iterator();
639 }
640 return *this;
641 }
642
643 template<typename _Bi_iter,
644 typename _Ch_type,
645 typename _Rx_traits>
646 void
647 regex_token_iterator<_Bi_iter, _Ch_type, _Rx_traits>::
648 _M_init(_Bi_iter __a, _Bi_iter __b)
649 {
650 _M_has_m1 = false;
651 for (auto __it : _M_subs)
652 if (__it == -1)
653 {
654 _M_has_m1 = true;
655 break;
656 }
657 if (_M_position != _Position())
658 _M_result = &_M_current_match();
659 else if (_M_has_m1)
660 {
661 _M_suffix.matched = true;
662 _M_suffix.first = __a;
663 _M_suffix.second = __b;
664 _M_result = &_M_suffix;
665 }
666 else
667 _M_result = nullptr;
668 }
669
670 _GLIBCXX_END_NAMESPACE_VERSION
671 } // namespace