Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:42

0001 //  (C) Copyright Gennadiy Rozental 2001.
0002 //  Use, modification, and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 //  See http://www.boost.org/libs/test for the library home page.
0007 //
0008 //!@file
0009 //!@brief CLA parser
0010 // ***************************************************************************
0011 
0012 #ifndef BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
0013 #define BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP
0014 
0015 // Boost.Test Runtime parameters
0016 #include <boost/test/utils/runtime/argument.hpp>
0017 #include <boost/test/utils/runtime/modifier.hpp>
0018 #include <boost/test/utils/runtime/parameter.hpp>
0019 
0020 #include <boost/test/utils/runtime/cla/argv_traverser.hpp>
0021 
0022 // Boost.Test
0023 #include <boost/test/utils/foreach.hpp>
0024 #include <boost/test/utils/algorithm.hpp>
0025 #include <boost/test/detail/throw_exception.hpp>
0026 #include <boost/test/detail/global_typedef.hpp>
0027 
0028 #include <boost/algorithm/cxx11/all_of.hpp> // !! ?? unnecessary after cxx11
0029 
0030 // STL
0031 // !! ?? #include <unordered_set>
0032 #include <set>
0033 #include <iostream>
0034 
0035 #include <boost/test/detail/suppress_warnings.hpp>
0036 
0037 namespace boost {
0038 namespace runtime {
0039 namespace cla {
0040 
0041 // ************************************************************************** //
0042 // **************         runtime::cla::parameter_trie         ************** //
0043 // ************************************************************************** //
0044 
0045 namespace rt_cla_detail {
0046 
0047 struct parameter_trie;
0048 typedef shared_ptr<parameter_trie> parameter_trie_ptr;
0049 typedef std::map<char,parameter_trie_ptr> trie_per_char;
0050 typedef std::vector<boost::reference_wrapper<parameter_cla_id const> > param_cla_id_list;
0051 
0052 struct parameter_trie {
0053     parameter_trie() : m_has_final_candidate( false ) {}
0054 
0055     /// If subtrie corresponding to the char c exists returns it otherwise creates new
0056     parameter_trie_ptr  make_subtrie( char c )
0057     {
0058         trie_per_char::const_iterator it = m_subtrie.find( c );
0059 
0060         if( it == m_subtrie.end() )
0061             it = m_subtrie.insert( std::make_pair( c, parameter_trie_ptr( new parameter_trie ) ) ).first;
0062 
0063         return it->second;
0064     }
0065 
0066     /// Creates series of sub-tries per characters in a string
0067     parameter_trie_ptr  make_subtrie( cstring s )
0068     {
0069         parameter_trie_ptr res;
0070 
0071         BOOST_TEST_FOREACH( char, c, s )
0072             res = (res ? res->make_subtrie( c ) : make_subtrie( c ));
0073 
0074         return res;
0075     }
0076 
0077     /// Registers candidate parameter for this subtrie. If final, it needs to be unique
0078     void                add_candidate_id( parameter_cla_id const& param_id, basic_param_ptr param_candidate, bool final )
0079     {
0080         BOOST_TEST_I_ASSRT( !m_has_final_candidate && (!final || m_id_candidates.empty()),
0081           conflicting_param() << "Parameter cla id " << param_id.m_tag << " conflicts with the "
0082                               << "parameter cla id " << m_id_candidates.back().get().m_tag );
0083 
0084         m_has_final_candidate = final;
0085         m_id_candidates.push_back( ref(param_id) );
0086 
0087         if( m_id_candidates.size() == 1 )
0088             m_param_candidate = param_candidate;
0089         else
0090             m_param_candidate.reset();
0091     }
0092 
0093     /// Gets subtrie for specified char if present or nullptr otherwise
0094     parameter_trie_ptr  get_subtrie( char c ) const
0095     {
0096         trie_per_char::const_iterator it = m_subtrie.find( c );
0097 
0098         return it != m_subtrie.end() ? it->second : parameter_trie_ptr();
0099     }
0100 
0101     // Data members
0102     trie_per_char       m_subtrie;
0103     param_cla_id_list   m_id_candidates;
0104     basic_param_ptr     m_param_candidate;
0105     bool                m_has_final_candidate;
0106 };
0107 
0108 // ************************************************************************** //
0109 // **************      runtime::cla::report_foreing_token      ************** //
0110 // ************************************************************************** //
0111 
0112 static void
0113 report_foreing_token( cstring program_name, cstring token )
0114 {
0115     std::cerr << "Boost.Test WARNING: token \"" << token << "\" does not correspond to the Boost.Test argument \n"
0116               << "                    and should be placed after all Boost.Test arguments and the -- separator.\n"
0117               << "                    For example: " << program_name << " --random -- " << token << "\n";
0118 }
0119 
0120 } // namespace rt_cla_detail
0121 
0122 // ************************************************************************** //
0123 // **************             runtime::cla::parser             ************** //
0124 // ************************************************************************** //
0125 
0126 class parser {
0127 public:
0128     /// Initializes a parser and builds internal trie representation used for
0129     /// parsing based on the supplied parameters
0130 #ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
0131     template<typename Modifiers=nfp::no_params_type>
0132     parser( parameters_store const& parameters, Modifiers const& m = nfp::no_params )
0133 #else
0134     template<typename Modifiers>
0135     parser( parameters_store const& parameters, Modifiers const& m )
0136 #endif
0137     {
0138         nfp::opt_assign( m_end_of_param_indicator, m, end_of_params );
0139         nfp::opt_assign( m_negation_prefix, m, negation_prefix );
0140 
0141         BOOST_TEST_I_ASSRT( algorithm::all_of( m_end_of_param_indicator.begin(),
0142                                                m_end_of_param_indicator.end(),
0143                                                parameter_cla_id::valid_prefix_char ),
0144                             invalid_cla_id() << "End of parameters indicator can only consist of prefix characters." );
0145 
0146         BOOST_TEST_I_ASSRT( algorithm::all_of( m_negation_prefix.begin(),
0147                                                m_negation_prefix.end(),
0148                                                parameter_cla_id::valid_name_char ),
0149                             invalid_cla_id() << "Negation prefix can only consist of prefix characters." );
0150 
0151         build_trie( parameters );
0152     }
0153 
0154     // input processing method
0155     int
0156     parse( int argc, char** argv, runtime::arguments_store& res )
0157     {
0158         // save program name for help message
0159         m_program_name = argv[0];
0160         cstring path_sep( "\\/" );
0161 
0162         cstring::iterator it = unit_test::utils::find_last_of( m_program_name.begin(), m_program_name.end(),
0163                                                                 path_sep.begin(), path_sep.end() );
0164         if( it != m_program_name.end() )
0165             m_program_name.trim_left( it + 1 );
0166 
0167         // Set up the traverser
0168         argv_traverser tr( argc, (char const**)argv );
0169 
0170         // Loop till we reach end of input
0171         while( !tr.eoi() ) {
0172             cstring curr_token = tr.current_token();
0173 
0174             cstring prefix;
0175             cstring name;
0176             cstring value_separator;
0177             bool    negative_form = false;
0178 
0179             // Perform format validations and split the argument into prefix, name and separator
0180             // False return value indicates end of params indicator is met
0181             if( !validate_token_format( curr_token, prefix, name, value_separator, negative_form ) ) {
0182                 // get rid of "end of params" token
0183                 tr.next_token();
0184                 break;
0185             }
0186 
0187             // Locate trie corresponding to found prefix and skip it in the input
0188             trie_ptr curr_trie = m_param_trie[prefix];
0189 
0190             if( !curr_trie ) {
0191                 //  format_error() << "Unrecognized parameter prefix in the argument " << tr.current_token()
0192                 rt_cla_detail::report_foreing_token( m_program_name, curr_token );
0193                 tr.save_token();
0194                 continue;
0195             }
0196 
0197             curr_token.trim_left( prefix.size() );
0198 
0199             // Locate parameter based on a name and skip it in the input
0200             locate_result locate_res = locate_parameter( curr_trie, name, curr_token );
0201             parameter_cla_id const& found_id    = locate_res.first;
0202             basic_param_ptr         found_param = locate_res.second;
0203 
0204             if( negative_form ) {
0205                 BOOST_TEST_I_ASSRT( found_id.m_negatable,
0206                                     format_error( found_param->p_name )
0207                                         << "Parameter tag " << found_id.m_tag << " is not negatable." );
0208 
0209                 curr_token.trim_left( m_negation_prefix.size() );
0210             }
0211 
0212             curr_token.trim_left( name.size() );
0213 
0214             bool should_go_to_next = true;
0215             cstring value;
0216 
0217 
0218             // Skip validations if parameter has optional value and we are at the end of token
0219             if( !value_separator.is_empty() || !found_param->p_has_optional_value ) {
0220 
0221                 // we are given a separator or there is no optional value
0222 
0223                 // Validate and skip value separator in the input
0224                 BOOST_TEST_I_ASSRT( found_id.m_value_separator == value_separator,
0225                                     format_error( found_param->p_name )
0226                                         << "Invalid separator for the parameter "
0227                                         << found_param->p_name
0228                                         << " in the argument " << tr.current_token() );
0229 
0230                 curr_token.trim_left( value_separator.size() );
0231 
0232                 // Deduce value source
0233                 value = curr_token;
0234                 if( value.is_empty() ) {
0235                     tr.next_token();
0236                     value = tr.current_token();
0237                 }
0238 
0239                 BOOST_TEST_I_ASSRT( !value.is_empty(),
0240                                     format_error( found_param->p_name )
0241                                         << "Missing an argument value for the parameter "
0242                                         << found_param->p_name
0243                                         << " in the argument " << tr.current_token() );
0244             }
0245             else if( (value_separator.is_empty() && found_id.m_value_separator.empty()) ) {
0246                 // Deduce value source
0247                 value = curr_token;
0248                 if( value.is_empty() ) {
0249                     tr.next_token(); // tokenization broke the value, we check the next one
0250 
0251                     if(!found_param->p_has_optional_value) {
0252                         // there is no separator and there is no optional value
0253                         // we look for the value on the next token
0254                         // example "-t XXXX" (no default)
0255                         // and we commit this value as being the passed value
0256                         value = tr.current_token();
0257                     }
0258                     else {
0259                         // there is no separator and the value is optional
0260                         // we check the next token
0261                         // example "-c" (defaults to true)
0262                         // and commit this as the value if this is not a token
0263                         cstring value_check = tr.current_token();
0264 
0265                         cstring prefix_test, name_test, value_separator_test;
0266                         bool negative_form_test;
0267                         if( validate_token_format( value_check, prefix_test, name_test, value_separator_test, negative_form_test )
0268                             && m_param_trie[prefix_test]) {
0269                           // this is a token, we consume what we have
0270                           should_go_to_next = false;
0271                         }
0272                         else {
0273                           // this is a value, we commit it
0274                           value = value_check;
0275                         }
0276                     }
0277                 }
0278             }
0279 
0280             // Validate against argument duplication
0281             BOOST_TEST_I_ASSRT( !res.has( found_param->p_name ) || found_param->p_repeatable,
0282                                 duplicate_arg( found_param->p_name )
0283                                     << "Duplicate argument value for the parameter "
0284                                     << found_param->p_name
0285                                     << " in the argument " << tr.current_token() );
0286 
0287             // Produce argument value
0288             found_param->produce_argument( value, negative_form, res );
0289 
0290             if(should_go_to_next) {
0291                 tr.next_token();
0292             }
0293         }
0294 
0295         // generate the remainder and return it's size
0296         return tr.remainder();
0297     }
0298 
0299     // help/usage/version
0300     void
0301     version( std::ostream& ostr )
0302     {
0303        ostr << "Boost.Test module ";
0304 
0305 #if defined(BOOST_TEST_MODULE)
0306        // we do not want to refer to the master test suite there
0307        ostr << '\'' << BOOST_TEST_STRINGIZE( BOOST_TEST_MODULE ).trim( "\"" ) << "' ";
0308 #endif
0309 
0310        ostr << "in executable '" << m_program_name << "'\n";
0311        ostr << "Compiled from Boost version "
0312             << BOOST_VERSION/100000      << "."
0313             << BOOST_VERSION/100 % 1000  << "."
0314             << BOOST_VERSION % 100       ;
0315        ostr << " with ";
0316 #if defined(BOOST_TEST_INCLUDED)
0317        ostr << "header-only inclusion of";
0318 #elif defined(BOOST_TEST_DYN_LINK)
0319        ostr << "dynamic linking to";
0320 #else
0321        ostr << "static linking to";
0322 #endif
0323        ostr << " Boost.Test\n";
0324        ostr << "- Compiler: " << BOOST_COMPILER << '\n'
0325             << "- Platform: " << BOOST_PLATFORM << '\n'
0326             << "- STL     : " << BOOST_STDLIB;
0327        ostr << std::endl;
0328     }
0329 
0330     void
0331     usage(std::ostream& ostr,
0332           cstring param_name = cstring(),
0333           bool use_color = true)
0334     {
0335         namespace utils = unit_test::utils;
0336         namespace ut_detail = unit_test::ut_detail;
0337 
0338         if( !param_name.is_empty() ) {
0339             basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
0340             param->usage( ostr, m_negation_prefix );
0341         }
0342         else {
0343             ostr << "\n  The program '" << m_program_name << "' is a Boost.Test module containing unit tests.";
0344 
0345             {
0346               BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
0347               ostr << "\n\n  Usage\n    ";
0348             }
0349 
0350             {
0351                 BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
0352                 ostr << m_program_name << " [Boost.Test argument]... ";
0353             }
0354             if( !m_end_of_param_indicator.empty() ) {
0355                 BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
0356                 ostr << '[' << m_end_of_param_indicator << " [custom test module argument]...]";
0357             }
0358         }
0359 
0360         ostr << "\n\n  Use\n      ";
0361         {
0362 
0363             BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
0364             ostr << m_program_name << " --help";
0365         }
0366         ostr << "\n  or  ";
0367         {
0368             BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::GREEN );
0369             ostr << m_program_name << " --help=<parameter name>";
0370         }
0371         ostr << "\n  for detailed help on Boost.Test parameters.\n";
0372     }
0373 
0374     void
0375     help(std::ostream& ostr,
0376          parameters_store const& parameters,
0377          cstring param_name,
0378          bool use_color = true)
0379     {
0380         namespace utils = unit_test::utils;
0381         namespace ut_detail = unit_test::ut_detail;
0382 
0383         if( !param_name.is_empty() ) {
0384             basic_param_ptr param = locate_parameter( m_param_trie[help_prefix], param_name, "" ).second;
0385             param->help( ostr, m_negation_prefix, use_color);
0386             return;
0387         }
0388 
0389         usage(ostr, cstring(), use_color);
0390 
0391         ostr << "\n\n";
0392         {
0393           BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
0394           ostr << "  Command line flags:\n";
0395         }
0396         runtime::commandline_pretty_print(
0397             ostr,
0398             "   ",
0399             "The command line flags of Boost.Test are listed below. "
0400             "All parameters are optional. You can specify parameter value either "
0401             "as a command line argument or as a value of its corresponding environment "
0402             "variable. If a flag is specified as a command line argument and an environment variable "
0403             "at the same time, the command line takes precedence. "
0404             "The command line argument "
0405             "support name guessing, and works with shorter names as long as those are not ambiguous."
0406         );
0407 
0408         if( !m_end_of_param_indicator.empty() ) {
0409             ostr << "\n\n   All the arguments after the '";
0410             {
0411                 BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::YELLOW );
0412                 ostr << m_end_of_param_indicator;
0413             }
0414             ostr << "' are ignored by Boost.Test.";
0415         }
0416 
0417 
0418         {
0419           BOOST_TEST_SCOPE_SETCOLOR( use_color, ostr, term_attr::BRIGHT, term_color::ORIGINAL );
0420           ostr << "\n\n  Environment variables:\n";
0421         }
0422         runtime::commandline_pretty_print(
0423             ostr,
0424             "   ",
0425             "Every argument listed below may also be set by a corresponding environment"
0426             "variable. For an argument '--argument_x=<value>', the corresponding "
0427             "environment variable is 'BOOST_TEST_ARGUMENT_X=value"
0428         );
0429 
0430 
0431 
0432         ostr << "\n\n  The following parameters are supported:\n";
0433 
0434         BOOST_TEST_FOREACH(
0435             parameters_store::storage_type::value_type const&,
0436             v,
0437             parameters.all() )
0438         {
0439             basic_param_ptr param = v.second;
0440             ostr << "\n";
0441             param->usage( ostr, m_negation_prefix, use_color);
0442         }
0443 
0444     }
0445 
0446 private:
0447     typedef rt_cla_detail::parameter_trie_ptr   trie_ptr;
0448     typedef rt_cla_detail::trie_per_char        trie_per_char;
0449     typedef std::map<cstring,trie_ptr>          str_to_trie;
0450 
0451     void
0452     build_trie( parameters_store const& parameters )
0453     {
0454         // Iterate over all parameters
0455         BOOST_TEST_FOREACH( parameters_store::storage_type::value_type const&, v, parameters.all() ) {
0456             basic_param_ptr param = v.second;
0457 
0458             // Register all parameter's ids in trie.
0459             BOOST_TEST_FOREACH( parameter_cla_id const&, id, param->cla_ids() ) {
0460                 // This is the trie corresponding to the prefix.
0461                 trie_ptr next_trie = m_param_trie[id.m_prefix];
0462                 if( !next_trie )
0463                     next_trie = m_param_trie[id.m_prefix] = trie_ptr( new rt_cla_detail::parameter_trie );
0464 
0465                 // Build the trie, by following name's characters
0466                 // and register this parameter as candidate on each level
0467                 for( size_t index = 0; index < id.m_tag.size(); ++index ) {
0468                     next_trie = next_trie->make_subtrie( id.m_tag[index] );
0469 
0470                     next_trie->add_candidate_id( id, param, index == (id.m_tag.size() - 1) );
0471                 }
0472             }
0473         }
0474     }
0475 
0476     bool
0477     validate_token_format( cstring token, cstring& prefix, cstring& name, cstring& separator, bool& negative_form )
0478     {
0479         // Match prefix
0480         cstring::iterator it = token.begin();
0481         while( it != token.end() && parameter_cla_id::valid_prefix_char( *it ) )
0482             ++it;
0483 
0484         prefix.assign( token.begin(), it );
0485 
0486         if( prefix.empty() )
0487             return true;
0488 
0489         // Match name
0490         while( it != token.end() && parameter_cla_id::valid_name_char( *it ) )
0491             ++it;
0492 
0493         name.assign( prefix.end(), it );
0494 
0495         if( name.empty() ) {
0496             if( prefix == m_end_of_param_indicator )
0497                 return false;
0498 
0499             BOOST_TEST_I_THROW( format_error() << "Invalid format for an actual argument " << token );
0500         }
0501 
0502         // Match value separator
0503         while( it != token.end() && parameter_cla_id::valid_separator_char( *it ) )
0504             ++it;
0505 
0506         separator.assign( name.end(), it );
0507 
0508         // Match negation prefix
0509         negative_form = !m_negation_prefix.empty() && ( name.substr( 0, m_negation_prefix.size() ) == m_negation_prefix );
0510         if( negative_form )
0511             name.trim_left( m_negation_prefix.size() );
0512 
0513         return true;
0514     }
0515 
0516     // C++03: cannot have references as types
0517     typedef std::pair<parameter_cla_id, basic_param_ptr> locate_result;
0518 
0519     locate_result
0520     locate_parameter( trie_ptr curr_trie, cstring name, cstring token )
0521     {
0522         std::vector<trie_ptr> typo_candidates;
0523         std::vector<trie_ptr> next_typo_candidates;
0524         trie_ptr next_trie;
0525 
0526         BOOST_TEST_FOREACH( char, c, name ) {
0527             if( curr_trie ) {
0528                 // locate next subtrie corresponding to the char
0529                 next_trie = curr_trie->get_subtrie( c );
0530 
0531                 if( next_trie )
0532                     curr_trie = next_trie;
0533                 else {
0534                     // Initiate search for typo candicates. We will account for 'wrong char' typo
0535                     // 'missing char' typo and 'extra char' typo
0536                     BOOST_TEST_FOREACH( trie_per_char::value_type const&, typo_cand, curr_trie->m_subtrie ) {
0537                         // 'wrong char' typo
0538                         typo_candidates.push_back( typo_cand.second );
0539 
0540                         // 'missing char' typo
0541                         if( (next_trie = typo_cand.second->get_subtrie( c )) )
0542                             typo_candidates.push_back( next_trie );
0543                     }
0544 
0545                     // 'extra char' typo
0546                     typo_candidates.push_back( curr_trie );
0547 
0548                     curr_trie.reset();
0549                 }
0550             }
0551             else {
0552                 // go over existing typo candidates and see if they are still viable
0553                 BOOST_TEST_FOREACH( trie_ptr, typo_cand, typo_candidates ) {
0554                     trie_ptr next_typo_cand = typo_cand->get_subtrie( c );
0555 
0556                     if( next_typo_cand )
0557                         next_typo_candidates.push_back( next_typo_cand );
0558                 }
0559 
0560                 next_typo_candidates.swap( typo_candidates );
0561                 next_typo_candidates.clear();
0562             }
0563         }
0564 
0565         if( !curr_trie ) {
0566             std::vector<cstring> typo_candidate_names;
0567             std::set<parameter_cla_id const*> unique_typo_candidate; // !! ?? unordered_set
0568             typo_candidate_names.reserve( typo_candidates.size() );
0569 // !! ??            unique_typo_candidate.reserve( typo_candidates.size() );
0570 
0571             BOOST_TEST_FOREACH( trie_ptr, trie_cand, typo_candidates ) {
0572                 // avoid ambiguos candidate trie
0573                 if( trie_cand->m_id_candidates.size() > 1 )
0574                     continue;
0575 
0576                 BOOST_TEST_FOREACH( parameter_cla_id const&, param_cand, trie_cand->m_id_candidates ) {
0577                     if( !unique_typo_candidate.insert( &param_cand ).second )
0578                         continue;
0579 
0580                     typo_candidate_names.push_back( param_cand.m_tag );
0581                 }
0582             }
0583 
0584 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
0585             BOOST_TEST_I_THROW( unrecognized_param( std::move(typo_candidate_names) )
0586                                 << "An unrecognized parameter in the argument "
0587                                 << token );
0588 #else
0589             BOOST_TEST_I_THROW( unrecognized_param( typo_candidate_names )
0590                                 << "An unrecognized parameter in the argument "
0591                                 << token );
0592 #endif
0593         }
0594 
0595         if( curr_trie->m_id_candidates.size() > 1 ) {
0596             std::vector<cstring> amb_names;
0597             BOOST_TEST_FOREACH( parameter_cla_id const&, param_id, curr_trie->m_id_candidates )
0598                 amb_names.push_back( param_id.m_tag );
0599 
0600 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
0601             BOOST_TEST_I_THROW( ambiguous_param( std::move( amb_names ) )
0602                                 << "An ambiguous parameter name in the argument " << token );
0603 #else
0604             BOOST_TEST_I_THROW( ambiguous_param( amb_names )
0605                                 << "An ambiguous parameter name in the argument " << token );
0606 #endif
0607         }
0608 
0609         return locate_result( curr_trie->m_id_candidates.back().get(), curr_trie->m_param_candidate );
0610     }
0611 
0612     // Data members
0613     cstring     m_program_name;
0614     std::string m_end_of_param_indicator;
0615     std::string m_negation_prefix;
0616     str_to_trie m_param_trie;
0617 };
0618 
0619 } // namespace cla
0620 } // namespace runtime
0621 } // namespace boost
0622 
0623 #include <boost/test/detail/enable_warnings.hpp>
0624 
0625 #endif // BOOST_TEST_UTILS_RUNTIME_CLA_PARSER_HPP