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