mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Updated embedded Clara to 0.0.2.3
- has all new, more robust, token parsing. - eliminates issue with unreachable code - allows use of forward slashes to introduce short args on Windows
This commit is contained in:
		| @@ -131,10 +131,10 @@ namespace Catch { | |||||||
|             Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; |             Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int applyCommandLine( int argc, char const* argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { |         int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { | ||||||
|             try { |             try { | ||||||
|                 m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); |                 m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); | ||||||
|                 m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); |                 m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); | ||||||
|                 if( m_configData.showHelp ) |                 if( m_configData.showHelp ) | ||||||
|                     showHelp( m_configData.processName ); |                     showHelp( m_configData.processName ); | ||||||
|                 m_config.reset(); |                 m_config.reset(); | ||||||
| @@ -158,16 +158,13 @@ namespace Catch { | |||||||
|             m_config.reset(); |             m_config.reset(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int run( int argc, char const* argv[] ) { |         int run( int argc, char const* const* const argv ) { | ||||||
|  |  | ||||||
|             int returnCode = applyCommandLine( argc, argv ); |             int returnCode = applyCommandLine( argc, argv ); | ||||||
|             if( returnCode == 0 ) |             if( returnCode == 0 ) | ||||||
|                 returnCode = run(); |                 returnCode = run(); | ||||||
|             return returnCode; |             return returnCode; | ||||||
|         } |         } | ||||||
|         int run( int argc, char* argv[] ) { |  | ||||||
|             return run( argc, const_cast<char const**>( argv ) ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int run() { |         int run() { | ||||||
|             if( m_configData.showHelp ) |             if( m_configData.showHelp ) | ||||||
|   | |||||||
							
								
								
									
										164
									
								
								include/external/clara.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										164
									
								
								include/external/clara.h
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ | |||||||
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| // Version 0.0.1.1 | // Version 0.0.2.3 | ||||||
|  |  | ||||||
| // Only use header guard if we are not using an outer namespace | // Only use header guard if we are not using an outer namespace | ||||||
| #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) | #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) | ||||||
| @@ -343,6 +343,11 @@ namespace Tbc { | |||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <memory> | #include <memory> | ||||||
|  |  | ||||||
|  | #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) | ||||||
|  | #define CLARA_PLATFORM_WINDOWS | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| // Use optional outer namespace | // Use optional outer namespace | ||||||
| #ifdef STITCH_CLARA_OPEN_NAMESPACE | #ifdef STITCH_CLARA_OPEN_NAMESPACE | ||||||
| STITCH_CLARA_OPEN_NAMESPACE | STITCH_CLARA_OPEN_NAMESPACE | ||||||
| @@ -366,9 +371,6 @@ namespace Clara { | |||||||
|     const unsigned int consoleWidth = 80; |     const unsigned int consoleWidth = 80; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|         // Use this to try and stop compiler from warning about unreachable code |  | ||||||
|         inline bool isTrue( bool value ) { return value; } |  | ||||||
|  |  | ||||||
|         using namespace Tbc; |         using namespace Tbc; | ||||||
|  |  | ||||||
|         inline bool startsWith( std::string const& str, std::string const& prefix ) { |         inline bool startsWith( std::string const& str, std::string const& prefix ) { | ||||||
| @@ -404,14 +406,7 @@ namespace Clara { | |||||||
|             else |             else | ||||||
|                 throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" ); |                 throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" ); | ||||||
|         } |         } | ||||||
|         inline void convertInto( bool _source, bool& _dest ) { |  | ||||||
|             _dest = _source; |  | ||||||
|         } |  | ||||||
|         template<typename T> |  | ||||||
|         inline void convertInto( bool, T& ) { |  | ||||||
|             if( isTrue( true ) ) |  | ||||||
|                 throw std::runtime_error( "Invalid conversion" ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         template<typename ConfigT> |         template<typename ConfigT> | ||||||
|         struct IArgFunction { |         struct IArgFunction { | ||||||
| @@ -421,7 +416,6 @@ namespace Clara { | |||||||
|             IArgFunction( IArgFunction const& ) = default; |             IArgFunction( IArgFunction const& ) = default; | ||||||
| #endif | #endif | ||||||
|             virtual void set( ConfigT& config, std::string const& value ) const = 0; |             virtual void set( ConfigT& config, std::string const& value ) const = 0; | ||||||
|             virtual void setFlag( ConfigT& config ) const = 0; |  | ||||||
|             virtual bool takesArg() const = 0; |             virtual bool takesArg() const = 0; | ||||||
|             virtual IArgFunction* clone() const = 0; |             virtual IArgFunction* clone() const = 0; | ||||||
|         }; |         }; | ||||||
| @@ -443,9 +437,6 @@ namespace Clara { | |||||||
|             void set( ConfigT& config, std::string const& value ) const { |             void set( ConfigT& config, std::string const& value ) const { | ||||||
|                 functionObj->set( config, value ); |                 functionObj->set( config, value ); | ||||||
|             } |             } | ||||||
|             void setFlag( ConfigT& config ) const { |  | ||||||
|                 functionObj->setFlag( config ); |  | ||||||
|             } |  | ||||||
|             bool takesArg() const { return functionObj->takesArg(); } |             bool takesArg() const { return functionObj->takesArg(); } | ||||||
|  |  | ||||||
|             bool isSet() const { |             bool isSet() const { | ||||||
| @@ -459,7 +450,6 @@ namespace Clara { | |||||||
|         template<typename C> |         template<typename C> | ||||||
|         struct NullBinder : IArgFunction<C>{ |         struct NullBinder : IArgFunction<C>{ | ||||||
|             virtual void set( C&, std::string const& ) const {} |             virtual void set( C&, std::string const& ) const {} | ||||||
|             virtual void setFlag( C& ) const {} |  | ||||||
|             virtual bool takesArg() const { return true; } |             virtual bool takesArg() const { return true; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } |             virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } | ||||||
|         }; |         }; | ||||||
| @@ -470,9 +460,6 @@ namespace Clara { | |||||||
|             virtual void set( C& p, std::string const& stringValue ) const { |             virtual void set( C& p, std::string const& stringValue ) const { | ||||||
|                 convertInto( stringValue, p.*member ); |                 convertInto( stringValue, p.*member ); | ||||||
|             } |             } | ||||||
|             virtual void setFlag( C& p ) const { |  | ||||||
|                 convertInto( true, p.*member ); |  | ||||||
|             } |  | ||||||
|             virtual bool takesArg() const { return !IsBool<M>::value; } |             virtual bool takesArg() const { return !IsBool<M>::value; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } |             virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } | ||||||
|             M C::* member; |             M C::* member; | ||||||
| @@ -485,11 +472,6 @@ namespace Clara { | |||||||
|                 convertInto( stringValue, value ); |                 convertInto( stringValue, value ); | ||||||
|                 (p.*member)( value ); |                 (p.*member)( value ); | ||||||
|             } |             } | ||||||
|             virtual void setFlag( C& p ) const { |  | ||||||
|                 typename RemoveConstRef<M>::type value; |  | ||||||
|                 convertInto( true, value ); |  | ||||||
|                 (p.*member)( value ); |  | ||||||
|             } |  | ||||||
|             virtual bool takesArg() const { return !IsBool<M>::value; } |             virtual bool takesArg() const { return !IsBool<M>::value; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } |             virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } | ||||||
|             void (C::*member)( M ); |             void (C::*member)( M ); | ||||||
| @@ -503,9 +485,6 @@ namespace Clara { | |||||||
|                 if( value ) |                 if( value ) | ||||||
|                     (p.*member)(); |                     (p.*member)(); | ||||||
|             } |             } | ||||||
|             virtual void setFlag( C& p ) const { |  | ||||||
|                 (p.*member)(); |  | ||||||
|             } |  | ||||||
|             virtual bool takesArg() const { return false; } |             virtual bool takesArg() const { return false; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } |             virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } | ||||||
|             void (C::*member)(); |             void (C::*member)(); | ||||||
| @@ -520,9 +499,6 @@ namespace Clara { | |||||||
|                 if( value ) |                 if( value ) | ||||||
|                     function( obj ); |                     function( obj ); | ||||||
|             } |             } | ||||||
|             virtual void setFlag( C& p ) const { |  | ||||||
|                 function( p ); |  | ||||||
|             } |  | ||||||
|             virtual bool takesArg() const { return false; } |             virtual bool takesArg() const { return false; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } |             virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } | ||||||
|             void (*function)( C& ); |             void (*function)( C& ); | ||||||
| @@ -536,11 +512,6 @@ namespace Clara { | |||||||
|                 convertInto( stringValue, value ); |                 convertInto( stringValue, value ); | ||||||
|                 function( obj, value ); |                 function( obj, value ); | ||||||
|             } |             } | ||||||
|             virtual void setFlag( C& obj ) const { |  | ||||||
|                 typename RemoveConstRef<T>::type value; |  | ||||||
|                 convertInto( true, value ); |  | ||||||
|                 function( obj, value ); |  | ||||||
|             } |  | ||||||
|             virtual bool takesArg() const { return !IsBool<T>::value; } |             virtual bool takesArg() const { return !IsBool<T>::value; } | ||||||
|             virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } |             virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } | ||||||
|             void (*function)( C&, T ); |             void (*function)( C&, T ); | ||||||
| @@ -548,8 +519,20 @@ namespace Clara { | |||||||
|  |  | ||||||
|     } // namespace Detail |     } // namespace Detail | ||||||
|  |  | ||||||
|     struct Parser { |     inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { | ||||||
|         Parser() : separators( " \t=:" ) {} |         std::vector<std::string> args( static_cast<std::size_t>( argc ) ); | ||||||
|  |         for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i ) | ||||||
|  |             args[i] = argv[i]; | ||||||
|  |  | ||||||
|  |         return args; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     class Parser { | ||||||
|  |         enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; | ||||||
|  |         Mode mode; | ||||||
|  |         std::size_t from; | ||||||
|  |         bool inQuotes; | ||||||
|  |     public: | ||||||
|  |  | ||||||
|         struct Token { |         struct Token { | ||||||
|             enum Type { Positional, ShortOpt, LongOpt }; |             enum Type { Positional, ShortOpt, LongOpt }; | ||||||
| @@ -558,38 +541,75 @@ namespace Clara { | |||||||
|             std::string data; |             std::string data; | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         void parseIntoTokens( int argc, char const* const argv[], std::vector<Parser::Token>& tokens ) const { |         Parser() : mode( None ), from( 0 ), inQuotes( false ){} | ||||||
|  |  | ||||||
|  |         void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) { | ||||||
|             const std::string doubleDash = "--"; |             const std::string doubleDash = "--"; | ||||||
|             for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) |             for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) | ||||||
|                 parseIntoTokens( argv[i] , tokens); |                 parseIntoTokens( args[i], tokens); | ||||||
|         } |         } | ||||||
|         void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { |  | ||||||
|             while( !arg.empty() ) { |         void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { | ||||||
|                 Parser::Token token( Parser::Token::Positional, arg ); |             for( std::size_t i = 0; i <= arg.size(); ++i ) { | ||||||
|                 arg = ""; |                 char c = arg[i]; | ||||||
|                 if( token.data[0] == '-' ) { |                 if( c == '"' ) | ||||||
|                     if( token.data.size() > 1 && token.data[1] == '-' ) { |                     inQuotes = !inQuotes; | ||||||
|                         token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); |                 mode = handleMode( i, c, arg, tokens ); | ||||||
|                     } |  | ||||||
|                     else { |  | ||||||
|                         token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); |  | ||||||
|                         if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { |  | ||||||
|                             arg = "-" + token.data.substr( 1 ); |  | ||||||
|                             token.data = token.data.substr( 0, 1 ); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 if( token.type != Parser::Token::Positional ) { |  | ||||||
|                     std::size_t pos = token.data.find_first_of( separators ); |  | ||||||
|                     if( pos != std::string::npos ) { |  | ||||||
|                         arg = token.data.substr( pos+1 ); |  | ||||||
|                         token.data = token.data.substr( 0, pos ); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 tokens.push_back( token ); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         std::string separators; |         Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | ||||||
|  |             switch( mode ) { | ||||||
|  |                 case None: return handleNone( i, c ); | ||||||
|  |                 case MaybeShortOpt: return handleMaybeShortOpt( i, c ); | ||||||
|  |                 case ShortOpt: | ||||||
|  |                 case LongOpt: | ||||||
|  |                 case SlashOpt: return handleOpt( i, c, arg, tokens ); | ||||||
|  |                 case Positional: return handlePositional( i, c, arg, tokens ); | ||||||
|  |                 default: throw std::logic_error( "Unknown mode" ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Mode handleNone( std::size_t i, char c ) { | ||||||
|  |             if( inQuotes ) { | ||||||
|  |                 from = i; | ||||||
|  |                 return Positional; | ||||||
|  |             } | ||||||
|  |             switch( c ) { | ||||||
|  |                 case '-': return MaybeShortOpt; | ||||||
|  | #ifdef CLARA_PLATFORM_WINDOWS | ||||||
|  |                 case '/': from = i+1; return SlashOpt; | ||||||
|  | #endif | ||||||
|  |                 default: from = i; return Positional; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Mode handleMaybeShortOpt( std::size_t i, char c ) { | ||||||
|  |             switch( c ) { | ||||||
|  |                 case '-': from = i+1; return LongOpt; | ||||||
|  |                 default: from = i; return ShortOpt; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | ||||||
|  |             if( std::string( " \t:=\0", 5 ).find( c ) == std::string::npos ) | ||||||
|  |                 return mode; | ||||||
|  |  | ||||||
|  |             std::string optName = arg.substr( from, i-from ); | ||||||
|  |             if( mode == ShortOpt ) | ||||||
|  |                 for( std::size_t j = 0; j < optName.size(); ++j ) | ||||||
|  |                     tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); | ||||||
|  |             else if( mode == SlashOpt && optName.size() == 1 ) | ||||||
|  |                 tokens.push_back( Token( Token::ShortOpt, optName ) ); | ||||||
|  |             else | ||||||
|  |                 tokens.push_back( Token( Token::LongOpt, optName ) ); | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|  |         Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | ||||||
|  |             if( inQuotes || std::string( " \t\0", 3 ).find( c ) == std::string::npos ) | ||||||
|  |                 return mode; | ||||||
|  |  | ||||||
|  |             std::string data = arg.substr( from, i-from ); | ||||||
|  |             tokens.push_back( Token( Token::Positional, data ) ); | ||||||
|  |             return None; | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     template<typename ConfigT> |     template<typename ConfigT> | ||||||
| @@ -894,21 +914,21 @@ namespace Clara { | |||||||
|             return oss.str(); |             return oss.str(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         ConfigT parse( int argc, char const* const argv[] ) const { |         ConfigT parse( std::vector<std::string> const& args ) const { | ||||||
|             ConfigT config; |             ConfigT config; | ||||||
|             parseInto( argc, argv, config ); |             parseInto( args, config ); | ||||||
|             return config; |             return config; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { |         std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { | ||||||
|             std::string processName = argv[0]; |             std::string processName = args[0]; | ||||||
|             std::size_t lastSlash = processName.find_last_of( "/\\" ); |             std::size_t lastSlash = processName.find_last_of( "/\\" ); | ||||||
|             if( lastSlash != std::string::npos ) |             if( lastSlash != std::string::npos ) | ||||||
|                 processName = processName.substr( lastSlash+1 ); |                 processName = processName.substr( lastSlash+1 ); | ||||||
|             m_boundProcessName.set( config, processName ); |             m_boundProcessName.set( config, processName ); | ||||||
|             std::vector<Parser::Token> tokens; |             std::vector<Parser::Token> tokens; | ||||||
|             Parser parser; |             Parser parser; | ||||||
|             parser.parseIntoTokens( argc, argv, tokens ); |             parser.parseIntoTokens( args, tokens ); | ||||||
|             return populate( tokens, config ); |             return populate( tokens, config ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -939,7 +959,7 @@ namespace Clara { | |||||||
|                                     arg.boundField.set( config, tokens[++i].data ); |                                     arg.boundField.set( config, tokens[++i].data ); | ||||||
|                             } |                             } | ||||||
|                             else { |                             else { | ||||||
|                                 arg.boundField.setFlag( config ); |                                 arg.boundField.set( config, "true" ); | ||||||
|                             } |                             } | ||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" ) | |||||||
| template<size_t size> | template<size_t size> | ||||||
| void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { | void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { | ||||||
|     Catch::Clara::CommandLine<Catch::ConfigData> parser = Catch::makeCommandLineParser(); |     Catch::Clara::CommandLine<Catch::ConfigData> parser = Catch::makeCommandLineParser(); | ||||||
|     parser.parseInto( size, argv, config ); |     parser.parseInto( Catch::Clara::argsToVector( size, argv ), config ); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<size_t size> | template<size_t size> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash