1  // -*- C++ -*-
       2  // regex utils for the C++ library testsuite.
       3  //
       4  // Copyright (C) 2012-2023 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
      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        }
     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        }
     120      catch (const logic_error& e)
     121        {
     122  	cout << "logic_error::what " << e.what() << endl;
     123  	throw;
     124        }
     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(__s, __e, __m, __re, __flags,
     147  				      _RegexExecutorPolicy::_S_auto,
     148  				      true);
     149        match_results<_Bi_iter, _Alloc> __mm;
     150        auto __res2 = __regex_algo_impl(__s, __e, __mm, __re, __flags,
     151  				      _RegexExecutorPolicy::_S_alternate,
     152  				      true);
     153        if (__res1 == __res2 && __m == __mm)
     154  	return __res1;
     155        throw std::exception();
     156      }
     157  
     158    // No match_results version
     159    template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits>
     160      inline bool
     161      regex_match_debug(_Bi_iter                                 __first,
     162  		      _Bi_iter                                 __last,
     163  		      const basic_regex<_Ch_type, _Rx_traits>& __re,
     164  		      match_flag_type                          __flags
     165  		      = std::regex_constants::match_default)
     166      {
     167        match_results<_Bi_iter> __what;
     168        return regex_match_debug(__first, __last, __what, __re, __flags);
     169      }
     170  
     171    // C-string version
     172    template<typename _Ch_type, typename _Alloc, typename _Rx_traits>
     173      inline bool
     174      regex_match_debug(const _Ch_type*                          __s,
     175  		      match_results<const _Ch_type*, _Alloc>&  __m,
     176  		      const basic_regex<_Ch_type, _Rx_traits>& __re,
     177  		      match_flag_type                          __f
     178  		      = std::regex_constants::match_default)
     179        { return regex_match_debug(__s, __s + _Rx_traits::length(__s),
     180  				 __m, __re, __f); }
     181  
     182    // C-string version without match_results
     183    template<typename _Ch_type, class _Rx_traits>
     184      inline bool
     185      regex_match_debug(const _Ch_type*                          __s,
     186  		      const basic_regex<_Ch_type, _Rx_traits>& __re,
     187  		      match_flag_type                          __f
     188  		      = std::regex_constants::match_default)
     189        { return regex_match_debug(__s, __s + _Rx_traits::length(__s),
     190  				 __re, __f); }
     191  
     192    // std::basic_string version
     193    template<typename _Ch_traits, typename _Ch_alloc,
     194             typename _Alloc, typename _Ch_type, typename _Rx_traits>
     195      inline bool
     196      regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits,
     197  			_Ch_alloc>& __s,
     198  		      match_results<typename std::basic_string<_Ch_type,
     199  			_Ch_traits, _Ch_alloc>::const_iterator,
     200  			_Alloc>& __m,
     201  		      const basic_regex<_Ch_type, _Rx_traits>& __re,
     202  		      match_flag_type                          __flags
     203  		      = std::regex_constants::match_default)
     204        { return regex_match_debug(__s.begin(), __s.end(),
     205  				 __m, __re, __flags); }
     206  
     207    // std::basic_string version without match_results
     208    template<typename _Ch_traits, typename _Str_allocator,
     209             typename _Ch_type, typename _Rx_traits>
     210      inline bool
     211      regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits,
     212  		      _Str_allocator>&                         __s,
     213  		      const basic_regex<_Ch_type, _Rx_traits>& __re,
     214  		      match_flag_type                          __flags
     215  		      = std::regex_constants::match_default)
     216      { return regex_match_debug(__s.begin(), __s.end(), __re, __flags); }
     217  
     218    // regex_match_debug behaves like regex_match, but will run *two* executors
     219    // (if there's no back-reference) and check if their results agree. If not,
     220    // an exception throws. One can use them just in the way of using regex_match.
     221    template<typename _Bi_iter, typename _Alloc,
     222             typename _Ch_type, typename _Rx_traits>
     223      bool
     224      regex_search_debug(_Bi_iter                                 __s,
     225  		       _Bi_iter                                 __e,
     226  		       match_results<_Bi_iter, _Alloc>&         __m,
     227  		       const basic_regex<_Ch_type, _Rx_traits>& __re,
     228  		       match_flag_type   __flags
     229  		       = std::regex_constants::match_default)
     230      {
     231        using namespace std::__detail;
     232        auto __res1 = __regex_algo_impl(__s, __e, __m, __re, __flags,
     233  				      _RegexExecutorPolicy::_S_auto,
     234  				      false);
     235        match_results<_Bi_iter, _Alloc> __mm;
     236        auto __res2 = __regex_algo_impl(__s, __e, __mm, __re, __flags,
     237  				      _RegexExecutorPolicy::_S_alternate,
     238  				      false);
     239        if (__res1 == __res2 && __m == __mm)
     240          return __res1;
     241        throw(std::exception()); // Let test fail. Give it a name.
     242      }
     243  
     244    // No match_results version
     245    template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits>
     246      inline bool
     247      regex_search_debug(_Bi_iter                                 __first,
     248  		       _Bi_iter                                 __last,
     249  		       const basic_regex<_Ch_type, _Rx_traits>& __re,
     250  		       match_flag_type                          __flags
     251  		       = std::regex_constants::match_default)
     252      {
     253        match_results<_Bi_iter> __what;
     254        return regex_search_debug(__first, __last, __what, __re, __flags);
     255      }
     256  
     257    // C-string version
     258    template<typename _Ch_type, class _Alloc, class _Rx_traits>
     259      inline bool
     260      regex_search_debug(const _Ch_type*                          __s,
     261  		       match_results<const _Ch_type*, _Alloc>&  __m,
     262  		       const basic_regex<_Ch_type, _Rx_traits>& __e,
     263  		       match_flag_type                          __f
     264  		       = std::regex_constants::match_default)
     265      { return regex_search_debug(__s, __s + _Rx_traits::length(__s),
     266  				__m, __e, __f); }
     267  
     268    // C-string version without match_results
     269    template<typename _Ch_type, typename _Rx_traits>
     270      inline bool
     271      regex_search_debug(const _Ch_type*                          __s,
     272  		       const basic_regex<_Ch_type, _Rx_traits>& __e,
     273  		       match_flag_type                          __f
     274  		       = std::regex_constants::match_default)
     275      { return regex_search_debug(__s, __s + _Rx_traits::length(__s),
     276  				__e, __f); }
     277  
     278    // std::basic_string version
     279    template<typename _Ch_traits, typename _Ch_alloc,
     280             typename _Alloc, typename _Ch_type,
     281             typename _Rx_traits>
     282      inline bool
     283      regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits,
     284  		       _Ch_alloc>& __s,
     285  		       match_results<typename std::basic_string<_Ch_type,
     286  		       _Ch_traits, _Ch_alloc>::const_iterator, _Alloc>&
     287  		       __m,
     288  		       const basic_regex<_Ch_type, _Rx_traits>& __e,
     289  		       match_flag_type                          __f
     290  		       = std::regex_constants::match_default)
     291      { return regex_search_debug(__s.begin(), __s.end(), __m, __e, __f); }
     292  
     293    // std::basic_string version without match_results
     294    template<typename _Ch_traits, typename _String_allocator,
     295             typename _Ch_type, typename _Rx_traits>
     296      inline bool
     297      regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits,
     298  		       _String_allocator>&                      __s,
     299  		       const basic_regex<_Ch_type, _Rx_traits>& __e,
     300  		       match_flag_type                          __f
     301  		       = std::regex_constants::match_default)
     302      { return regex_search_debug(__s.begin(), __s.end(), __e, __f); }
     303  
     304  } // namespace __gnu_test
     305  #endif