1 // -*- C++ -*-
2 // regex utils for the C++ library testsuite.
3 //
4 // Copyright (C) 2012-2019 Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 //
12 // This library 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.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING3.  If not see
19 // <http://www.gnu.org/licenses/>.
20 //
21 
22 #ifndef _TESTSUITE_REGEX_H
23 #define _TESTSUITE_REGEX_H 1
24 
25 #include <regex>
26 #include <stdexcept>
27 #include <iostream>
28 
29 namespace __gnu_test
30 {
31   // Test on a compilation of simple expressions, throw regex_error on error.
32   typedef std::regex				regex_type;
33   typedef regex_type::flag_type			flag_type;
34   typedef std::regex_constants::match_flag_type	match_flag_type;
35   typedef std::regex_constants::error_type	error_type;
36   typedef std::size_t				size_type;
37   typedef std::string				string_type;
38   using std::basic_regex;
39   using std::match_results;
40 
41   // Utilities
42   struct regex_expected_fail { };
43 
44   const error_type regex_error_internal(static_cast<error_type>(-1));
45 
46   // Stringify error codes for text logging.
47   const char* regex_error_codes[] =
48     {
49     "error_collate",
50     "error_ctype",
51     "error_escape",
52     "error_backref",
53     "error_brack",
54     "error_paren",
55     "error_brace",
56     "error_badbrace",
57     "error_range",
58     "error_space",
59     "error_badrepeat",
60     "error_complexity",
61     "error_stack"
62   };
63 
64   void
show_regex_error_codes()65   show_regex_error_codes()
66   {
67     using namespace std;
68     using namespace std::regex_constants;
69     const char tab('\t');
70     cout << "error_collate =   " << tab << error_collate << endl;
71     cout << "error_ctype =     " << tab << error_ctype << endl;
72     cout << "error_escape =    " << tab << error_escape << endl;
73     cout << "error_backref =   " << tab << error_backref << endl;
74     cout << "error_brack =     " << tab << error_brack << endl;
75     cout << "error_paren =     " << tab << error_paren << endl;
76     cout << "error_brace =     " << tab << error_brace << endl;
77     cout << "error_badbrace =  " << tab << error_badbrace << endl;
78     cout << "error_range =     " << tab << error_range << endl;
79     cout << "error_space =     " << tab << error_space << endl;
80     cout << "error_badrepeat = " << tab << error_badrepeat << endl;
81     cout << "error_complexity =" << tab << error_complexity << endl;
82     cout << "error_stack =     " << tab << error_stack << endl;
83   }
84 
85   // Arguments
86   // string __res: the regular expression string
87   // flag_type __f: flag
88   // __error: expected error, if any
89   void
90   regex_sanity_check(const string_type& __res,
91 		     flag_type __f = regex_type::basic,
92 		     error_type __error =  regex_error_internal)
93   {
94     using namespace std;
95 
96     try
97       {
98 	regex_type reo(__res, __f);
99 	auto n = reo.mark_count();
100 	cout << "regex_type::mark_count " << n << endl;
101       }
catch(const regex_error & e)102     catch (const regex_error& e)
103       {
104 	cout << "regex_sanity_check: "  << __res << endl;
105 	cout << "regex_error::what " << e.what() << endl;
106 
107 	show_regex_error_codes();
108 	cout << "regex_error::code " << regex_error_codes[e.code()] << endl;
109 
110 	if (__error != regex_error_internal)
111 	  {
112 	    // Then expected error_type is __error. Check.
113 	    if (__error != e.code())
114 	      {
115 		throw regex_expected_fail();
116 	      }
117 	  }
118 	throw;
119       }
catch(const logic_error & e)120     catch (const logic_error& e)
121       {
122 	cout << "logic_error::what " << e.what() << endl;
123 	throw;
124       }
catch(const std::exception & e)125     catch (const std::exception& e)
126       {
127 	cout << "exception: " << endl;
128 	throw;
129       }
130   }
131 
132   // regex_match_debug behaves like regex_match, but will run *two* executors
133   // (if there's no back-reference) and check if their results agree. If not,
134   // an exception is thrown. The arguments are the same as for regex_match.
135   template<typename _Bi_iter, typename _Alloc,
136 	   typename _Ch_type, typename _Rx_traits>
137     bool
138     regex_match_debug(_Bi_iter                                 __s,
139 		      _Bi_iter                                 __e,
140 		      match_results<_Bi_iter, _Alloc>&         __m,
141 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
142 		      match_flag_type                          __flags
143 		      = std::regex_constants::match_default)
144     {
145       using namespace std::__detail;
146       auto __res1 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits,
147 	   _RegexExecutorPolicy::_S_auto, true>
148 	(__s, __e, __m, __re, __flags);
149       match_results<_Bi_iter, _Alloc> __mm;
150       auto __res2 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits,
151 	   _RegexExecutorPolicy::_S_alternate, true>
152 	(__s, __e, __mm, __re, __flags);
153       // __m is unspecified if return value is false.
154       if (__res1 == __res2 && (!__res1 || __m == __mm))
155 	return __res1;
156       throw std::exception();
157     }
158 
159   // No match_results version
160   template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits>
161     inline bool
162     regex_match_debug(_Bi_iter                                 __first,
163 		      _Bi_iter                                 __last,
164 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
165 		      match_flag_type                          __flags
166 		      = std::regex_constants::match_default)
167     {
168       match_results<_Bi_iter> __what;
169       return regex_match_debug(__first, __last, __what, __re, __flags);
170     }
171 
172   // C-string version
173   template<typename _Ch_type, typename _Alloc, typename _Rx_traits>
174     inline bool
175     regex_match_debug(const _Ch_type*                          __s,
176 		      match_results<const _Ch_type*, _Alloc>&  __m,
177 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
178 		      match_flag_type                          __f
179 		      = std::regex_constants::match_default)
180       { return regex_match_debug(__s, __s + _Rx_traits::length(__s),
181 				 __m, __re, __f); }
182 
183   // C-string version without match_results
184   template<typename _Ch_type, class _Rx_traits>
185     inline bool
186     regex_match_debug(const _Ch_type*                          __s,
187 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
188 		      match_flag_type                          __f
189 		      = std::regex_constants::match_default)
190       { return regex_match_debug(__s, __s + _Rx_traits::length(__s),
191 				 __re, __f); }
192 
193   // std::basic_string version
194   template<typename _Ch_traits, typename _Ch_alloc,
195            typename _Alloc, typename _Ch_type, typename _Rx_traits>
196     inline bool
197     regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits,
198 			_Ch_alloc>& __s,
199 		      match_results<typename std::basic_string<_Ch_type,
200 			_Ch_traits, _Ch_alloc>::const_iterator,
201 			_Alloc>& __m,
202 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
203 		      match_flag_type                          __flags
204 		      = std::regex_constants::match_default)
205       { return regex_match_debug(__s.begin(), __s.end(),
206 				 __m, __re, __flags); }
207 
208   // std::basic_string version without match_results
209   template<typename _Ch_traits, typename _Str_allocator,
210            typename _Ch_type, typename _Rx_traits>
211     inline bool
212     regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits,
213 		      _Str_allocator>&                         __s,
214 		      const basic_regex<_Ch_type, _Rx_traits>& __re,
215 		      match_flag_type                          __flags
216 		      = std::regex_constants::match_default)
217     { return regex_match_debug(__s.begin(), __s.end(), __re, __flags); }
218 
219   // regex_match_debug behaves like regex_match, but will run *two* executors
220   // (if there's no back-reference) and check if their results agree. If not,
221   // an exception throws. One can use them just in the way of using regex_match.
222   template<typename _Bi_iter, typename _Alloc,
223            typename _Ch_type, typename _Rx_traits>
224     bool
225     regex_search_debug(_Bi_iter                                 __s,
226 		       _Bi_iter                                 __e,
227 		       match_results<_Bi_iter, _Alloc>&         __m,
228 		       const basic_regex<_Ch_type, _Rx_traits>& __re,
229 		       match_flag_type   __flags
230 		       = std::regex_constants::match_default)
231     {
232       using namespace std::__detail;
233       auto __res1 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits,
234 	   _RegexExecutorPolicy::_S_auto, false>
235         (__s, __e, __m, __re, __flags);
236       match_results<_Bi_iter, _Alloc> __mm;
237       auto __res2 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits,
238 	   _RegexExecutorPolicy::_S_alternate, false>
239         (__s, __e, __mm, __re, __flags);
240       if (__res1 == __res2 && __m == __mm)
241         return __res1;
242       throw(std::exception()); // Let test fail. Give it a name.
243     }
244 
245   // No match_results version
246   template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits>
247     inline bool
248     regex_search_debug(_Bi_iter                                 __first,
249 		       _Bi_iter                                 __last,
250 		       const basic_regex<_Ch_type, _Rx_traits>& __re,
251 		       match_flag_type                          __flags
252 		       = std::regex_constants::match_default)
253     {
254       match_results<_Bi_iter> __what;
255       return regex_search_debug(__first, __last, __what, __re, __flags);
256     }
257 
258   // C-string version
259   template<typename _Ch_type, class _Alloc, class _Rx_traits>
260     inline bool
261     regex_search_debug(const _Ch_type*                          __s,
262 		       match_results<const _Ch_type*, _Alloc>&  __m,
263 		       const basic_regex<_Ch_type, _Rx_traits>& __e,
264 		       match_flag_type                          __f
265 		       = std::regex_constants::match_default)
266     { return regex_search_debug(__s, __s + _Rx_traits::length(__s),
267 				__m, __e, __f); }
268 
269   // C-string version without match_results
270   template<typename _Ch_type, typename _Rx_traits>
271     inline bool
272     regex_search_debug(const _Ch_type*                          __s,
273 		       const basic_regex<_Ch_type, _Rx_traits>& __e,
274 		       match_flag_type                          __f
275 		       = std::regex_constants::match_default)
276     { return regex_search_debug(__s, __s + _Rx_traits::length(__s),
277 				__e, __f); }
278 
279   // std::basic_string version
280   template<typename _Ch_traits, typename _Ch_alloc,
281            typename _Alloc, typename _Ch_type,
282            typename _Rx_traits>
283     inline bool
284     regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits,
285 		       _Ch_alloc>& __s,
286 		       match_results<typename std::basic_string<_Ch_type,
287 		       _Ch_traits, _Ch_alloc>::const_iterator, _Alloc>&
288 		       __m,
289 		       const basic_regex<_Ch_type, _Rx_traits>& __e,
290 		       match_flag_type                          __f
291 		       = std::regex_constants::match_default)
292     { return regex_search_debug(__s.begin(), __s.end(), __m, __e, __f); }
293 
294   // std::basic_string version without match_results
295   template<typename _Ch_traits, typename _String_allocator,
296            typename _Ch_type, typename _Rx_traits>
297     inline bool
298     regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits,
299 		       _String_allocator>&                      __s,
300 		       const basic_regex<_Ch_type, _Rx_traits>& __e,
301 		       match_flag_type                          __f
302 		       = std::regex_constants::match_default)
303     { return regex_search_debug(__s.begin(), __s.end(), __e, __f); }
304 
305 } // namespace __gnu_test
306 #endif
307