mirror of
https://github.com/boostorg/test.git
synced 2026-01-23 18:12:12 +00:00
291 lines
7.5 KiB
C++
Executable File
291 lines
7.5 KiB
C++
Executable File
// (C) Copyright Gennadiy Rozental 2001-2005.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
// See http://www.boost.org/libs/test for the library home page.
|
|
|
|
// Boost.Runtime.Param
|
|
#include <boost/test/utils/runtime/cla/named_parameter.hpp>
|
|
#include <boost/test/utils/runtime/cla/parser.hpp>
|
|
|
|
namespace rt = boost::runtime;
|
|
namespace cla = boost::runtime::cla;
|
|
|
|
// STL
|
|
#include <iostream>
|
|
#include <iterator>
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
struct Point : std::pair<int,int> {
|
|
bool parse( rt::cstring& in ) {
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != '(' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
rt::cstring::size_type pos = in.find( ")" );
|
|
|
|
if( pos == rt::cstring::npos )
|
|
return false;
|
|
|
|
rt::cstring ss( in.begin(), pos );
|
|
pos = ss.find( "," );
|
|
|
|
if( pos == rt::cstring::npos )
|
|
return false;
|
|
|
|
rt::cstring f( ss.begin(), pos );
|
|
rt::cstring s( ss.begin()+pos+1, ss.end() );
|
|
|
|
f.trim();
|
|
s.trim();
|
|
|
|
try {
|
|
first = boost::lexical_cast<int>( f );
|
|
second = boost::lexical_cast<int>( s );
|
|
}
|
|
catch( boost::bad_lexical_cast const& ) {
|
|
return false;
|
|
}
|
|
|
|
in.trim_left( ss.end()+1 );
|
|
return true;
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<( std::ostream& ostr, Point const& p )
|
|
{
|
|
ostr << '(' << p.first << ',' << p.second << ')';
|
|
|
|
return ostr;
|
|
}
|
|
|
|
struct Segment : std::pair<Point,Point> {
|
|
bool parse( rt::cstring& in ) {
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != '[' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
|
|
if( !first.parse( in ) )
|
|
return false;
|
|
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != ',' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
|
|
if( !second.parse( in ) )
|
|
return false;
|
|
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != ']' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<( std::ostream& ostr, Segment const& p )
|
|
{
|
|
ostr << '[' << p.first << ',' << p.second << ']';
|
|
|
|
return ostr;
|
|
}
|
|
|
|
struct Circle : std::pair<Point,int> {
|
|
bool parse( rt::cstring& in ) {
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != '[' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
|
|
if( !first.parse( in ) )
|
|
return false;
|
|
|
|
in.trim_left();
|
|
|
|
if( first_char( in ) != ',' )
|
|
return false;
|
|
|
|
in.trim_left( 1 );
|
|
|
|
rt::cstring::size_type pos = in.find( "]" );
|
|
|
|
if( pos == rt::cstring::npos )
|
|
return false;
|
|
|
|
rt::cstring ss( in.begin(), pos );
|
|
ss.trim();
|
|
|
|
try {
|
|
second = boost::lexical_cast<int>( ss );
|
|
}
|
|
catch( boost::bad_lexical_cast const& ) {
|
|
return false;
|
|
}
|
|
|
|
in.trim_left( pos+1 );
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<( std::ostream& ostr, Circle const& p )
|
|
{
|
|
ostr << '[' << p.first << ',' << p.second << ']';
|
|
|
|
return ostr;
|
|
}
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
template<typename T>
|
|
class ShapeIdPolicy : public cla::identification_policy {
|
|
rt::cstring m_name;
|
|
rt::cstring m_usage_str;
|
|
public:
|
|
explicit ShapeIdPolicy( rt::cstring name )
|
|
: cla::identification_policy( boost::rtti::type_id<ShapeIdPolicy<T> >() )
|
|
, m_name( name ) {}
|
|
|
|
virtual bool responds_to( rt::cstring name ) const { return m_name == name; }
|
|
virtual bool conflict_with( cla::identification_policy const& ) const { return false; }
|
|
virtual rt::cstring id_2_report() const { return m_name; }
|
|
virtual void usage_info( rt::format_stream& fs ) const { fs << m_name; }
|
|
|
|
virtual bool matching( cla::parameter const& p, cla::argv_traverser& tr, bool primary ) const
|
|
{
|
|
T s;
|
|
|
|
rt::cstring in = tr.input();
|
|
return s.parse( in );
|
|
}
|
|
};
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
template<typename T>
|
|
class ShapeArgumentFactory : public cla::argument_factory {
|
|
rt::cstring m_usage_str;
|
|
public:
|
|
explicit ShapeArgumentFactory( rt::cstring usage ) : m_usage_str( usage ) {}
|
|
|
|
// Argument factory interface
|
|
virtual rt::argument_ptr produce_using( cla::parameter& p, cla::argv_traverser& tr )
|
|
{
|
|
T s;
|
|
|
|
rt::cstring in = tr.input();
|
|
s.parse( in );
|
|
tr.trim( in.begin() - tr.input().begin() );
|
|
|
|
if( !p.actual_argument() ) {
|
|
rt::argument_ptr res;
|
|
|
|
rt::typed_argument<std::list<T> >* new_arg = new rt::typed_argument<std::list<T> >( p );
|
|
|
|
new_arg->p_value.value.push_back( s );
|
|
res.reset( new_arg );
|
|
|
|
return res;
|
|
}
|
|
else {
|
|
std::list<T>& arg_values = rt::arg_value<std::list<T> >( *p.actual_argument() );
|
|
arg_values.push_back( s );
|
|
|
|
return p.actual_argument();
|
|
}
|
|
}
|
|
virtual rt::argument_ptr produce_using( cla::parameter& p, cla::parser const& ) { return rt::argument_ptr(); }
|
|
virtual void argument_usage_info( rt::format_stream& fs ) { fs << m_usage_str; }
|
|
};
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
struct SegmentParam : cla::parameter {
|
|
SegmentParam()
|
|
: cla::parameter( m_id_policy, m_arg_factory )
|
|
, m_id_policy( "segment" )
|
|
, m_arg_factory( ":((P1x,P1y), (P2x,P2y)) ... ((P1x,P1y), (P2x,P2y))" )
|
|
{}
|
|
|
|
ShapeIdPolicy<Segment> m_id_policy;
|
|
ShapeArgumentFactory<Segment> m_arg_factory;
|
|
};
|
|
|
|
inline boost::shared_ptr<SegmentParam>
|
|
segment_param() { return boost::shared_ptr<SegmentParam>( new SegmentParam ); }
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
struct CircleParam : cla::parameter {
|
|
CircleParam()
|
|
: cla::parameter( m_id_policy, m_arg_factory )
|
|
, m_id_policy( "circle" )
|
|
, m_arg_factory( ":((P1x,P1y), R) ... ((P1x,P1y), R)" )
|
|
{}
|
|
|
|
ShapeIdPolicy<Circle> m_id_policy;
|
|
ShapeArgumentFactory<Circle> m_arg_factory;
|
|
};
|
|
|
|
inline boost::shared_ptr<CircleParam>
|
|
circle_param() { return boost::shared_ptr<CircleParam>( new CircleParam ); }
|
|
|
|
//_____________________________________________________________________//
|
|
|
|
int main() {
|
|
char* argv[] = { "basic", "[(1,", "1)", ",", "(7,", "-1", ")]", "[(", "1,1)", ",7", "]", "[(3,", "1", ")", ",", "2]",
|
|
"[", "(2,7", "),", "(5", ",1", ")]" };
|
|
int argc = sizeof(argv)/sizeof(char*);
|
|
|
|
try {
|
|
cla::parser P;
|
|
|
|
P << circle_param() - cla::optional
|
|
<< segment_param() - cla::optional;
|
|
|
|
P.parse( argc, argv );
|
|
|
|
boost::optional<std::list<Segment> > segments;
|
|
boost::optional<std::list<Circle> > circles;
|
|
|
|
P.get( "segment", segments );
|
|
|
|
if( segments ) {
|
|
std::cout << "segments : ";
|
|
std::copy( segments->begin(), segments->end(), std::ostream_iterator<Segment>( std::cout, "; " ) );
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
P.get( "circle", circles );
|
|
|
|
if( circles ) {
|
|
std::cout << "circles : ";
|
|
std::copy( circles->begin(), circles->end(), std::ostream_iterator<Circle>( std::cout, "; " ) );
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
catch( rt::logic_error const& ex ) {
|
|
std::cout << "Logic error: " << ex.msg() << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// EOF
|