source: NonGTP/Boost/boost/test/utils/runtime/cla/parser.ipp @ 857

Revision 857, 8.7 KB checked in by igarcia, 18 years ago (diff)
Line 
1//  (C) Copyright Gennadiy Rozental 2005.
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: parser.ipp,v $
9//
10//  Version     : $Revision: 1.1 $
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                                       !new_param->conflict_with( *old_param ),
88            BOOST_RT_PARAM_LITERAL( "Definition of parameter " )                << new_param->id_2_report() <<
89            BOOST_RT_PARAM_LITERAL( " conflicts with defintion of parameter " ) << old_param->id_2_report() );
90    }
91
92    m_parameters.push_back( new_param );
93
94    return *this;
95}
96
97//____________________________________________________________________________//
98
99BOOST_RT_PARAM_INLINE void
100parser::parse( int& argc, char_type** argv )
101{
102    if( m_program_name.empty() ) {
103        m_program_name.assign( argv[0] );
104        dstring::size_type pos = m_program_name.find_last_of( BOOST_RT_PARAM_LITERAL( "/\\" ) );
105
106        if( pos != cstring::npos )
107            m_program_name.erase( 0, pos+1 );
108    }
109
110    m_traverser.init( argc, argv );
111
112    try {
113        while( !m_traverser.eoi() ) {
114            parameter_ptr found_param;
115
116            BOOST_RT_PARAM_TRACE( "Total " << m_parameters.size() << " parameters registered" );
117
118            BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
119                BOOST_RT_PARAM_TRACE( "Try parameter " << curr_param->id_2_report() );
120
121                if( curr_param->matching( m_traverser, !found_param ) ) {
122                    BOOST_RT_PARAM_TRACE( "Match found" );
123                    BOOST_RT_CLA_VALIDATE_INPUT( !found_param, (m_traverser.rollback(),m_traverser), "Ambiguous input" );
124
125                    found_param = curr_param;
126                }
127
128                m_traverser.rollback();
129            }
130
131            if( !found_param ) {
132                BOOST_RT_PARAM_TRACE( "No match found" );
133                BOOST_RT_CLA_VALIDATE_INPUT( m_traverser.handle_mismatch(), m_traverser,
134                                             BOOST_RT_PARAM_LITERAL( "Unexpected input" ) );
135
136                continue;
137            }
138
139            BOOST_RT_PARAM_TRACE( "Parse argument value" );
140            found_param->produce_argument( m_traverser );
141
142            m_traverser.commit();
143        }
144
145        BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
146            if( !curr_param->p_optional && !curr_param->actual_argument() ) {
147                curr_param->produce_argument( *this );
148
149                BOOST_RT_PARAM_VALIDATE_LOGIC( curr_param->actual_argument(),
150                    BOOST_RT_PARAM_LITERAL( "Required argument for parameter " ) << curr_param->id_2_report()
151                        << BOOST_RT_PARAM_LITERAL( " is missing" ) );
152            }
153        }
154    }
155    catch( bad_lexical_cast const& ) {
156        BOOST_RT_PARAM_REPORT_LOGIC_ERROR(
157            BOOST_RT_PARAM_LITERAL( "String to value convertion error during input parsing" ) );
158    }
159
160    m_traverser.remainder( argc, argv );
161}
162
163//____________________________________________________________________________//
164
165BOOST_RT_PARAM_INLINE const_argument_ptr
166parser::operator[]( cstring string_id ) const
167{
168    parameter_ptr found_param;
169
170    BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
171        if( curr_param->responds_to( string_id ) ) {
172            BOOST_RT_PARAM_VALIDATE_LOGIC( !found_param,
173                                           BOOST_RT_PARAM_LITERAL( "Ambiguous parameter string id: " ) << string_id );
174
175            found_param = curr_param;
176        }
177    }
178
179    BOOST_RT_PARAM_VALIDATE_LOGIC( found_param, BOOST_RT_PARAM_LITERAL( "Unknown parameter: " ) << string_id );
180
181    return found_param->actual_argument();
182}
183
184//____________________________________________________________________________//
185
186BOOST_RT_PARAM_INLINE cstring
187parser::get( cstring string_id ) const
188{
189    return get<cstring>( string_id );
190}
191
192//____________________________________________________________________________//
193
194BOOST_RT_PARAM_INLINE void
195parser::usage( out_stream& ostr )
196{
197    if( m_program_name.empty() )
198        assign_op( m_program_name, BOOST_RT_PARAM_CSTRING_LITERAL( "<program>" ), 0 );
199
200    format_stream fs;
201
202    fs << m_program_name;
203
204    BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
205        fs << BOOST_RT_PARAM_LITERAL( ' ' );
206
207        if( curr_param->p_optional )
208            fs << BOOST_RT_PARAM_LITERAL( '[' );
209
210        curr_param->usage_info( fs );
211
212        if( curr_param->p_optional )
213            fs << BOOST_RT_PARAM_LITERAL( ']' );
214
215        if( curr_param->p_multiplicable ) {
216            fs << BOOST_RT_PARAM_CSTRING_LITERAL( " ... " );
217           
218            if( curr_param->p_optional )
219                fs << BOOST_RT_PARAM_LITERAL( '[' );
220
221            curr_param->usage_info( fs );
222
223            if( curr_param->p_optional )
224                fs << BOOST_RT_PARAM_LITERAL( ']' );
225        }
226    }
227
228    ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "Usage:\n" ) << fs.str() << std::endl;
229}
230
231//____________________________________________________________________________//
232
233BOOST_RT_PARAM_INLINE void
234parser::help( out_stream& ostr )
235{
236    usage( ostr );
237
238    bool need_where = true;
239
240    BOOST_TEST_FOREACH( parameter_ptr const&, curr_param, m_parameters ) {
241        if( curr_param->p_description->empty() )
242            continue;
243
244        if( need_where ) {
245            ostr << BOOST_RT_PARAM_CSTRING_LITERAL( "where:\n" );
246            need_where = false;
247        }
248
249        ostr << curr_param->id_2_report() << BOOST_RT_PARAM_CSTRING_LITERAL( " - " ) << curr_param->p_description << std::endl;
250    }
251}
252
253//____________________________________________________________________________//
254
255} // namespace cla
256
257} // namespace BOOST_RT_PARAM_NAMESPACE
258
259} // namespace boost
260
261// ************************************************************************** //
262//   Revision History:
263//
264//   $Log: parser.ipp,v $
265//   Revision 1.1  2005/04/12 06:42:43  rogeeff
266//   Runtime.Param library initial commit
267//
268// ************************************************************************** //
269
270#endif // BOOST_RT_CLA_PARSER_IPP_062904GER
Note: See TracBrowser for help on using the repository browser.