parser.ipp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // (C) Copyright Gennadiy Rozental 2005-2008.
  2. // Use, modification, and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. // File : $RCSfile$
  8. //
  9. // Version : $Revision: 54633 $
  10. //
  11. // Description : implements parser - public interface for CLA parsing and accessing
  12. // ***************************************************************************
  13. #ifndef BOOST_RT_CLA_PARSER_IPP_062904GER
  14. #define BOOST_RT_CLA_PARSER_IPP_062904GER
  15. // Boost.Runtime.Parameter
  16. #include <boost/test/utils/runtime/config.hpp>
  17. #include <boost/test/utils/runtime/trace.hpp>
  18. #include <boost/test/utils/runtime/argument.hpp>
  19. #include <boost/test/utils/runtime/cla/argv_traverser.hpp>
  20. #include <boost/test/utils/runtime/cla/parameter.hpp>
  21. #include <boost/test/utils/runtime/cla/modifier.hpp>
  22. #include <boost/test/utils/runtime/cla/validation.hpp>
  23. #include <boost/test/utils/runtime/cla/parser.hpp>
  24. // Boost.Test
  25. #include <boost/test/utils/basic_cstring/io.hpp>
  26. #include <boost/test/utils/foreach.hpp>
  27. // Boost
  28. #include <boost/lexical_cast.hpp>
  29. namespace boost {
  30. namespace BOOST_RT_PARAM_NAMESPACE {
  31. namespace cla {
  32. // ************************************************************************** //
  33. // ************** runtime::cla::parser ************** //
  34. // ************************************************************************** //
  35. BOOST_RT_PARAM_INLINE
  36. parser::parser( cstring program_name )
  37. {
  38. assign_op( m_program_name, program_name, 0 );
  39. }
  40. //____________________________________________________________________________//
  41. BOOST_RT_PARAM_INLINE parser::param_iterator
  42. parser::first_param() const
  43. {
  44. return m_parameters.begin();
  45. }
  46. //____________________________________________________________________________//
  47. BOOST_RT_PARAM_INLINE parser::param_iterator
  48. parser::last_param() const
  49. {
  50. return m_parameters.end();
  51. }
  52. //____________________________________________________________________________//
  53. BOOST_RT_PARAM_INLINE argument const&
  54. parser::valid_argument( cstring string_id ) const
  55. {
  56. const_argument_ptr arg = (*this)[string_id];
  57. BOOST_RT_PARAM_VALIDATE_LOGIC( !!arg, "Actual argument for parameter " << string_id << " is not present" );
  58. return *arg;
  59. }
  60. //____________________________________________________________________________//
  61. BOOST_RT_PARAM_INLINE parser&
  62. parser::operator<<( parameter_ptr new_param )
  63. {
  64. BOOST_TEST_FOREACH( parameter_ptr, old_param, m_parameters ) {
  65. BOOST_RT_PARAM_VALIDATE_LOGIC( !old_param->conflict_with( *new_param ),
  66. BOOST_RT_PARAM_LITERAL( "Definition of parameter " ) << new_param->id_2_report() <<
  67. BOOST_RT_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() );
  68. }
  69. m_parameters.push_back( new_param );
  70. return *this;
  71. }
  72. //____________________________________________________________________________//
  73. BOOST_RT_PARAM_INLINE void
  74. parser::parse( int& argc, char_type** argv )
  75. {
  76. if( m_program_name.empty() ) {
  77. m_program_name.assign( argv[0] );
  78. dstring::size_type pos = m_program_name.find_last_of( BOOST_RT_PARAM_LITERAL( "/\\" ) );
  79. if( pos != static_cast<dstring::size_type>(cstring::npos) )
  80. m_program_name.erase( 0, pos+1 );
  81. }
  82. m_traverser.init( argc, argv );
  83. try {
  84. while( !m_traverser.eoi() ) {
  85. parameter_ptr found_param;
  86. BOOST_RT_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" );
  87. BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
  88. BOOST_RT_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() );
  89. if( curr_param->matching( m_traverser, !found_param ) ) {
  90. BOOST_RT_PARAM_TRACE( "Match found" );
  91. BOOST_RT_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" );
  92. found_param = curr_param;
  93. }
  94. m_traverser.rollback();
  95. }
  96. if( !found_param ) {
  97. BOOST_RT_PARAM_TRACE( "No match found" );
  98. BOOST_RT_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser,
  99. BOOST_RT_PARAM_LITERAL( "Unexpected input" ) );
  100. continue;
  101. }
  102. BOOST_RT_PARAM_TRACE( "Parse argument value" );
  103. found_param->produce_argument( m_traverser );
  104. m_traverser.commit();
  105. }
  106. BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
  107. if( !curr_param->p_optional && !curr_param->actual_argument() ) {
  108. curr_param->produce_argument( *this );
  109. BOOST_RT_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(),
  110. BOOST_RT_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report()
  111. << BOOST_RT_PARAM_LITERAL( " is missing" ) );
  112. }
  113. }
  114. }
  115. catch( bad_lexical_cast const& ) {
  116. BOOST_RT_PARAM_REPORT_LOGIC_ERROR(
  117. BOOST_RT_PARAM_LITERAL( "String to value convertion error during input parsing" ) );
  118. }
  119. m_traverser.remainder( argc, argv );
  120. }
  121. //____________________________________________________________________________//
  122. BOOST_RT_PARAM_INLINE const_argument_ptr
  123. parser::operator[]( cstring string_id ) const
  124. {
  125. parameter_ptr found_param;
  126. BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
  127. if( curr_param->responds_to( string_id ) ) {
  128. BOOST_RT_PARAM_VALIDATE_LOGIC( !found_param,
  129. BOOST_RT_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id );
  130. found_param = curr_param;
  131. }
  132. }
  133. return found_param ? found_param->actual_argument() : argument_ptr();
  134. }
  135. //____________________________________________________________________________//
  136. BOOST_RT_PARAM_INLINE cstring
  137. parser::get( cstring string_id ) const
  138. {
  139. return get<cstring>( string_id );
  140. }
  141. //____________________________________________________________________________//
  142. BOOST_RT_PARAM_INLINE void
  143. parser::usage( out_stream& ostr )
  144. {
  145. if( m_program_name.empty() )
  146. assign_op( m_program_name, BOOST_RT_PARAM_CSTRING_LITERAL( "<program>" ), 0 );
  147. format_stream fs;
  148. fs << m_program_name;
  149. BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
  150. fs << BOOST_RT_PARAM_LITERAL( ' ' );
  151. if( curr_param->p_optional )
  152. fs << BOOST_RT_PARAM_LITERAL( '[' );
  153. curr_param->usage_info( fs );
  154. if( curr_param->p_optional )
  155. fs << BOOST_RT_PARAM_LITERAL( ']' );
  156. if( curr_param->p_multiplicable ) {
  157. fs << BOOST_RT_PARAM_CSTRING_LITERAL( " ... " );
  158. if( curr_param->p_optional )
  159. fs << BOOST_RT_PARAM_LITERAL( '[' );
  160. curr_param->usage_info( fs );
  161. if( curr_param->p_optional )
  162. fs << BOOST_RT_PARAM_LITERAL( ']' );
  163. }
  164. }
  165. ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl;
  166. }
  167. //____________________________________________________________________________//
  168. BOOST_RT_PARAM_INLINE void
  169. parser::help( out_stream& ostr )
  170. {
  171. usage( ostr );
  172. bool need_where = true;
  173. BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
  174. if( curr_param->p_description->empty() )
  175. continue;
  176. if( need_where ) {
  177. ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "where:\n" );
  178. need_where = false;
  179. }
  180. ostr << curr_param->id_2_report() << BOOST_RT_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl;
  181. }
  182. }
  183. //____________________________________________________________________________//
  184. } // namespace cla
  185. } // namespace BOOST_RT_PARAM_NAMESPACE
  186. } // namespace boost
  187. #endif // BOOST_RT_CLA_PARSER_IPP_062904GER