Chris@16: // (C) Copyright Gennadiy Rozental 2005-2008. Chris@16: // Use, modification, and distribution are subject to the Chris@16: // Boost Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See http://www.boost.org/libs/test for the library home page. Chris@16: // Chris@16: // File : $RCSfile$ Chris@16: // Chris@101: // Version : $Revision$ Chris@16: // Chris@16: // Description : implements parser - public interface for CLA parsing and accessing Chris@16: // *************************************************************************** Chris@16: Chris@16: #ifndef BOOST_RT_CLA_PARSER_IPP_062904GER Chris@16: #define BOOST_RT_CLA_PARSER_IPP_062904GER Chris@16: Chris@16: // Boost.Runtime.Parameter Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // Boost.Test Chris@16: #include Chris@16: #include Chris@16: Chris@16: // Boost Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: namespace BOOST_RT_PARAM_NAMESPACE { Chris@16: Chris@16: namespace cla { Chris@16: Chris@16: // ************************************************************************** // Chris@16: // ************** runtime::cla::parser ************** // Chris@16: // ************************************************************************** // Chris@16: Chris@16: BOOST_RT_PARAM_INLINE Chris@16: parser::parser( cstring program_name ) Chris@16: { Chris@16: assign_op( m_program_name, program_name, 0 ); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE parser::param_iterator Chris@16: parser::first_param() const Chris@16: { Chris@16: return m_parameters.begin(); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE parser::param_iterator Chris@16: parser::last_param() const Chris@16: { Chris@16: return m_parameters.end(); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE argument const& Chris@16: parser::valid_argument( cstring string_id ) const Chris@16: { Chris@16: const_argument_ptr arg = (*this)[string_id]; Chris@16: Chris@16: BOOST_RT_PARAM_VALIDATE_LOGIC( !!arg, "Actual argument for parameter " << string_id << " is not present" ); Chris@16: Chris@16: return *arg; Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE parser& Chris@16: parser::operator<<( parameter_ptr new_param ) Chris@16: { Chris@16: BOOST_TEST_FOREACH( parameter_ptr, old_param, m_parameters ) { Chris@16: BOOST_RT_PARAM_VALIDATE_LOGIC( !old_param->conflict_with( *new_param ), Chris@16: BOOST_RT_PARAM_LITERAL( "Definition of parameter " ) << new_param->id_2_report() << Chris@16: BOOST_RT_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() ); Chris@16: } Chris@16: Chris@16: m_parameters.push_back( new_param ); Chris@16: Chris@16: return *this; Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE void Chris@16: parser::parse( int& argc, char_type** argv ) Chris@16: { Chris@16: if( m_program_name.empty() ) { Chris@16: m_program_name.assign( argv[0] ); Chris@16: dstring::size_type pos = m_program_name.find_last_of( BOOST_RT_PARAM_LITERAL( "/\\" ) ); Chris@16: Chris@16: if( pos != static_cast(cstring::npos) ) Chris@16: m_program_name.erase( 0, pos+1 ); Chris@16: } Chris@16: Chris@16: m_traverser.init( argc, argv ); Chris@16: Chris@16: try { Chris@16: while( !m_traverser.eoi() ) { Chris@16: parameter_ptr found_param; Chris@16: Chris@16: BOOST_RT_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" ); Chris@16: Chris@16: BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { Chris@16: BOOST_RT_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() ); Chris@16: Chris@16: if( curr_param->matching( m_traverser, !found_param ) ) { Chris@16: BOOST_RT_PARAM_TRACE( "Match found" ); Chris@16: BOOST_RT_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" ); Chris@16: Chris@16: found_param = curr_param; Chris@16: } Chris@16: Chris@16: m_traverser.rollback(); Chris@16: } Chris@16: Chris@16: if( !found_param ) { Chris@16: BOOST_RT_PARAM_TRACE( "No match found" ); Chris@16: BOOST_RT_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser, Chris@16: BOOST_RT_PARAM_LITERAL( "Unexpected input" ) ); Chris@16: Chris@16: continue; Chris@16: } Chris@16: Chris@16: BOOST_RT_PARAM_TRACE( "Parse argument value" ); Chris@16: found_param->produce_argument( m_traverser ); Chris@16: Chris@16: m_traverser.commit(); Chris@16: } Chris@16: Chris@16: BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { Chris@16: if( !curr_param->p_optional && !curr_param->actual_argument() ) { Chris@16: curr_param->produce_argument( *this ); Chris@16: Chris@16: BOOST_RT_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(), Chris@16: BOOST_RT_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report() Chris@16: << BOOST_RT_PARAM_LITERAL( " is missing" ) ); Chris@16: } Chris@16: } Chris@16: } Chris@16: catch( bad_lexical_cast const& ) { Chris@16: BOOST_RT_PARAM_REPORT_LOGIC_ERROR( Chris@16: BOOST_RT_PARAM_LITERAL( "String to value convertion error during input parsing" ) ); Chris@16: } Chris@16: Chris@16: m_traverser.remainder( argc, argv ); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE const_argument_ptr Chris@16: parser::operator[]( cstring string_id ) const Chris@16: { Chris@16: parameter_ptr found_param; Chris@16: Chris@16: BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { Chris@16: if( curr_param->responds_to( string_id ) ) { Chris@16: BOOST_RT_PARAM_VALIDATE_LOGIC( !found_param, Chris@16: BOOST_RT_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id ); Chris@16: Chris@16: found_param = curr_param; Chris@16: } Chris@16: } Chris@16: Chris@16: return found_param ? found_param->actual_argument() : argument_ptr(); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE cstring Chris@16: parser::get( cstring string_id ) const Chris@16: { Chris@16: return get( string_id ); Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE void Chris@16: parser::usage( out_stream& ostr ) Chris@16: { Chris@16: if( m_program_name.empty() ) Chris@16: assign_op( m_program_name, BOOST_RT_PARAM_CSTRING_LITERAL( "" ), 0 ); Chris@16: Chris@16: format_stream fs; Chris@16: Chris@16: fs << m_program_name; Chris@16: Chris@16: BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { Chris@16: fs << BOOST_RT_PARAM_LITERAL( ' ' ); Chris@16: Chris@16: if( curr_param->p_optional ) Chris@16: fs << BOOST_RT_PARAM_LITERAL( '[' ); Chris@16: Chris@16: curr_param->usage_info( fs ); Chris@16: Chris@16: if( curr_param->p_optional ) Chris@16: fs << BOOST_RT_PARAM_LITERAL( ']' ); Chris@16: Chris@16: if( curr_param->p_multiplicable ) { Chris@16: fs << BOOST_RT_PARAM_CSTRING_LITERAL( " ... " ); Chris@16: Chris@16: if( curr_param->p_optional ) Chris@16: fs << BOOST_RT_PARAM_LITERAL( '[' ); Chris@16: Chris@16: curr_param->usage_info( fs ); Chris@16: Chris@16: if( curr_param->p_optional ) Chris@16: fs << BOOST_RT_PARAM_LITERAL( ']' ); Chris@16: } Chris@16: } Chris@16: Chris@16: ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl; Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: BOOST_RT_PARAM_INLINE void Chris@16: parser::help( out_stream& ostr ) Chris@16: { Chris@16: usage( ostr ); Chris@16: Chris@16: bool need_where = true; Chris@16: Chris@16: BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { Chris@16: if( curr_param->p_description->empty() ) Chris@16: continue; Chris@16: Chris@16: if( need_where ) { Chris@16: ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "where:\n" ); Chris@16: need_where = false; Chris@16: } Chris@16: Chris@16: ostr << curr_param->id_2_report() << BOOST_RT_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl; Chris@16: } Chris@16: } Chris@16: Chris@16: //____________________________________________________________________________// Chris@16: Chris@16: } // namespace cla Chris@16: Chris@16: } // namespace BOOST_RT_PARAM_NAMESPACE Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_RT_CLA_PARSER_IPP_062904GER