| // (C) Copyright Gennadiy Rozental 2001-2008. |
| // 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 |