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