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 6// See http://www.boost.org/libs/test for the library home page. 7// 8// File : $RCSfile$ 9// 10// Version : $Revision: 54633 $ 11// 12// Description : implements parser - public interface for CLA parsing and accessing 13// *************************************************************************** 14 15#ifndef BOOST_RT_CLA_PARSER_IPP_062904GER 16#define BOOST_RT_CLA_PARSER_IPP_062904GER 17 18// Boost.Runtime.Parameter 19#include <boost/test/utils/runtime/config.hpp> 20#include <boost/test/utils/runtime/trace.hpp> 21#include <boost/test/utils/runtime/argument.hpp> 22 23#include <boost/test/utils/runtime/cla/argv_traverser.hpp> 24#include <boost/test/utils/runtime/cla/parameter.hpp> 25#include <boost/test/utils/runtime/cla/modifier.hpp> 26#include <boost/test/utils/runtime/cla/validation.hpp> 27#include <boost/test/utils/runtime/cla/parser.hpp> 28 29// Boost.Test 30#include <boost/test/utils/basic_cstring/io.hpp> 31#include <boost/test/utils/foreach.hpp> 32 33// Boost 34#include <boost/lexical_cast.hpp> 35 36namespace boost { 37 38namespace BOOST_RT_PARAM_NAMESPACE { 39 40namespace cla { 41 42// ************************************************************************** // 43// ************** runtime::cla::parser ************** // 44// ************************************************************************** // 45 46BOOST_RT_PARAM_INLINE 47parser::parser( cstring program_name ) 48{ 49 assign_op( m_program_name, program_name, 0 ); 50} 51 52//____________________________________________________________________________// 53 54BOOST_RT_PARAM_INLINE parser::param_iterator 55parser::first_param() const 56{ 57 return m_parameters.begin(); 58} 59 60//____________________________________________________________________________// 61 62BOOST_RT_PARAM_INLINE parser::param_iterator 63parser::last_param() const 64{ 65 return m_parameters.end(); 66} 67 68//____________________________________________________________________________// 69 70BOOST_RT_PARAM_INLINE argument const& 71parser::valid_argument( cstring string_id ) const 72{ 73 const_argument_ptr arg = (*this)[string_id]; 74 75 BOOST_RT_PARAM_VALIDATE_LOGIC( !!arg, "Actual argument for parameter " << string_id << " is not present" ); 76 77 return *arg; 78} 79 80//____________________________________________________________________________// 81 82BOOST_RT_PARAM_INLINE parser& 83parser::operator<<( parameter_ptr new_param ) 84{ 85 BOOST_TEST_FOREACH( parameter_ptr, old_param, m_parameters ) { 86 BOOST_RT_PARAM_VALIDATE_LOGIC( !old_param->conflict_with( *new_param ), 87 BOOST_RT_PARAM_LITERAL( "Definition of parameter " ) << new_param->id_2_report() << 88 BOOST_RT_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() ); 89 } 90 91 m_parameters.push_back( new_param ); 92 93 return *this; 94} 95 96//____________________________________________________________________________// 97 98BOOST_RT_PARAM_INLINE void 99parser::parse( int& argc, char_type** argv ) 100{ 101 if( m_program_name.empty() ) { 102 m_program_name.assign( argv[0] ); 103 dstring::size_type pos = m_program_name.find_last_of( BOOST_RT_PARAM_LITERAL( "/\\" ) ); 104 105 if( pos != static_cast<dstring::size_type>(cstring::npos) ) 106 m_program_name.erase( 0, pos+1 ); 107 } 108 109 m_traverser.init( argc, argv ); 110 111 try { 112 while( !m_traverser.eoi() ) { 113 parameter_ptr found_param; 114 115 BOOST_RT_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" ); 116 117 BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { 118 BOOST_RT_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() ); 119 120 if( curr_param->matching( m_traverser, !found_param ) ) { 121 BOOST_RT_PARAM_TRACE( "Match found" ); 122 BOOST_RT_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" ); 123 124 found_param = curr_param; 125 } 126 127 m_traverser.rollback(); 128 } 129 130 if( !found_param ) { 131 BOOST_RT_PARAM_TRACE( "No match found" ); 132 BOOST_RT_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser, 133 BOOST_RT_PARAM_LITERAL( "Unexpected input" ) ); 134 135 continue; 136 } 137 138 BOOST_RT_PARAM_TRACE( "Parse argument value" ); 139 found_param->produce_argument( m_traverser ); 140 141 m_traverser.commit(); 142 } 143 144 BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { 145 if( !curr_param->p_optional && !curr_param->actual_argument() ) { 146 curr_param->produce_argument( *this ); 147 148 BOOST_RT_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(), 149 BOOST_RT_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report() 150 << BOOST_RT_PARAM_LITERAL( " is missing" ) ); 151 } 152 } 153 } 154 catch( bad_lexical_cast const& ) { 155 BOOST_RT_PARAM_REPORT_LOGIC_ERROR( 156 BOOST_RT_PARAM_LITERAL( "String to value convertion error during input parsing" ) ); 157 } 158 159 m_traverser.remainder( argc, argv ); 160} 161 162//____________________________________________________________________________// 163 164BOOST_RT_PARAM_INLINE const_argument_ptr 165parser::operator[]( cstring string_id ) const 166{ 167 parameter_ptr found_param; 168 169 BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { 170 if( curr_param->responds_to( string_id ) ) { 171 BOOST_RT_PARAM_VALIDATE_LOGIC( !found_param, 172 BOOST_RT_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id ); 173 174 found_param = curr_param; 175 } 176 } 177 178 return found_param ? found_param->actual_argument() : argument_ptr(); 179} 180 181//____________________________________________________________________________// 182 183BOOST_RT_PARAM_INLINE cstring 184parser::get( cstring string_id ) const 185{ 186 return get<cstring>( string_id ); 187} 188 189//____________________________________________________________________________// 190 191BOOST_RT_PARAM_INLINE void 192parser::usage( out_stream& ostr ) 193{ 194 if( m_program_name.empty() ) 195 assign_op( m_program_name, BOOST_RT_PARAM_CSTRING_LITERAL( "<program>" ), 0 ); 196 197 format_stream fs; 198 199 fs << m_program_name; 200 201 BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { 202 fs << BOOST_RT_PARAM_LITERAL( ' ' ); 203 204 if( curr_param->p_optional ) 205 fs << BOOST_RT_PARAM_LITERAL( '[' ); 206 207 curr_param->usage_info( fs ); 208 209 if( curr_param->p_optional ) 210 fs << BOOST_RT_PARAM_LITERAL( ']' ); 211 212 if( curr_param->p_multiplicable ) { 213 fs << BOOST_RT_PARAM_CSTRING_LITERAL( " ... " ); 214 215 if( curr_param->p_optional ) 216 fs << BOOST_RT_PARAM_LITERAL( '[' ); 217 218 curr_param->usage_info( fs ); 219 220 if( curr_param->p_optional ) 221 fs << BOOST_RT_PARAM_LITERAL( ']' ); 222 } 223 } 224 225 ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl; 226} 227 228//____________________________________________________________________________// 229 230BOOST_RT_PARAM_INLINE void 231parser::help( out_stream& ostr ) 232{ 233 usage( ostr ); 234 235 bool need_where = true; 236 237 BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) { 238 if( curr_param->p_description->empty() ) 239 continue; 240 241 if( need_where ) { 242 ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "where:\n" ); 243 need_where = false; 244 } 245 246 ostr << curr_param->id_2_report() << BOOST_RT_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl; 247 } 248} 249 250//____________________________________________________________________________// 251 252} // namespace cla 253 254} // namespace BOOST_RT_PARAM_NAMESPACE 255 256} // namespace boost 257 258#endif // BOOST_RT_CLA_PARSER_IPP_062904GER 259