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; | ||||
|         } | ||||
|  | ||||
|         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 { | ||||
|                 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 ) | ||||
|                     showHelp( m_configData.processName ); | ||||
|                 m_config.reset(); | ||||
| @@ -158,16 +158,13 @@ namespace Catch { | ||||
|             m_config.reset(); | ||||
|         } | ||||
|  | ||||
|         int run( int argc, char const* argv[] ) { | ||||
|         int run( int argc, char const* const* const argv ) { | ||||
|  | ||||
|             int returnCode = applyCommandLine( argc, argv ); | ||||
|             if( returnCode == 0 ) | ||||
|                 returnCode = run(); | ||||
|             return returnCode; | ||||
|         } | ||||
|         int run( int argc, char* argv[] ) { | ||||
|             return run( argc, const_cast<char const**>( argv ) ); | ||||
|         } | ||||
|  | ||||
|         int run() { | ||||
|             if( m_configData.showHelp ) | ||||
|   | ||||
							
								
								
									
										156
									
								
								include/external/clara.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										156
									
								
								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) | ||||
|  */ | ||||
|  | ||||
| // Version 0.0.1.1 | ||||
| // Version 0.0.2.3 | ||||
|  | ||||
| // Only use header guard if we are not using an outer namespace | ||||
| #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) | ||||
| @@ -343,6 +343,11 @@ namespace Tbc { | ||||
| #include <stdexcept> | ||||
| #include <memory> | ||||
|  | ||||
| #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) | ||||
| #define CLARA_PLATFORM_WINDOWS | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Use optional outer namespace | ||||
| #ifdef STITCH_CLARA_OPEN_NAMESPACE | ||||
| STITCH_CLARA_OPEN_NAMESPACE | ||||
| @@ -366,9 +371,6 @@ namespace Clara { | ||||
|     const unsigned int consoleWidth = 80; | ||||
| #endif | ||||
|  | ||||
|         // Use this to try and stop compiler from warning about unreachable code | ||||
|         inline bool isTrue( bool value ) { return value; } | ||||
|  | ||||
|         using namespace Tbc; | ||||
|  | ||||
|         inline bool startsWith( std::string const& str, std::string const& prefix ) { | ||||
| @@ -404,14 +406,7 @@ namespace Clara { | ||||
|             else | ||||
|                 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> | ||||
|         struct IArgFunction { | ||||
| @@ -421,7 +416,6 @@ namespace Clara { | ||||
|             IArgFunction( IArgFunction const& ) = default; | ||||
| #endif | ||||
|             virtual void set( ConfigT& config, std::string const& value ) const = 0; | ||||
|             virtual void setFlag( ConfigT& config ) const = 0; | ||||
|             virtual bool takesArg() const = 0; | ||||
|             virtual IArgFunction* clone() const = 0; | ||||
|         }; | ||||
| @@ -443,9 +437,6 @@ namespace Clara { | ||||
|             void set( ConfigT& config, std::string const& value ) const { | ||||
|                 functionObj->set( config, value ); | ||||
|             } | ||||
|             void setFlag( ConfigT& config ) const { | ||||
|                 functionObj->setFlag( config ); | ||||
|             } | ||||
|             bool takesArg() const { return functionObj->takesArg(); } | ||||
|  | ||||
|             bool isSet() const { | ||||
| @@ -459,7 +450,6 @@ namespace Clara { | ||||
|         template<typename C> | ||||
|         struct NullBinder : IArgFunction<C>{ | ||||
|             virtual void set( C&, std::string const& ) const {} | ||||
|             virtual void setFlag( C& ) const {} | ||||
|             virtual bool takesArg() const { return true; } | ||||
|             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 { | ||||
|                 convertInto( stringValue, p.*member ); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 convertInto( true, p.*member ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return !IsBool<M>::value; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } | ||||
|             M C::* member; | ||||
| @@ -485,11 +472,6 @@ namespace Clara { | ||||
|                 convertInto( stringValue, 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 IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } | ||||
|             void (C::*member)( M ); | ||||
| @@ -503,9 +485,6 @@ namespace Clara { | ||||
|                 if( value ) | ||||
|                     (p.*member)(); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 (p.*member)(); | ||||
|             } | ||||
|             virtual bool takesArg() const { return false; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } | ||||
|             void (C::*member)(); | ||||
| @@ -520,9 +499,6 @@ namespace Clara { | ||||
|                 if( value ) | ||||
|                     function( obj ); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 function( p ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return false; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } | ||||
|             void (*function)( C& ); | ||||
| @@ -536,11 +512,6 @@ namespace Clara { | ||||
|                 convertInto( stringValue, 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 IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } | ||||
|             void (*function)( C&, T ); | ||||
| @@ -548,8 +519,20 @@ namespace Clara { | ||||
|  | ||||
|     } // namespace Detail | ||||
|  | ||||
|     struct Parser { | ||||
|         Parser() : separators( " \t=:" ) {} | ||||
|     inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { | ||||
|         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 { | ||||
|             enum Type { Positional, ShortOpt, LongOpt }; | ||||
| @@ -558,38 +541,75 @@ namespace Clara { | ||||
|             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 = "--"; | ||||
|             for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) | ||||
|                 parseIntoTokens( argv[i] , tokens); | ||||
|             for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) | ||||
|                 parseIntoTokens( args[i], tokens); | ||||
|         } | ||||
|         void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { | ||||
|             while( !arg.empty() ) { | ||||
|                 Parser::Token token( Parser::Token::Positional, arg ); | ||||
|                 arg = ""; | ||||
|                 if( token.data[0] == '-' ) { | ||||
|                     if( token.data.size() > 1 && token.data[1] == '-' ) { | ||||
|                         token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); | ||||
|                     } | ||||
|                     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 ); | ||||
|  | ||||
|         void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { | ||||
|             for( std::size_t i = 0; i <= arg.size(); ++i ) { | ||||
|                 char c = arg[i]; | ||||
|                 if( c == '"' ) | ||||
|                     inQuotes = !inQuotes; | ||||
|                 mode = handleMode( i, c, arg, tokens ); | ||||
|             } | ||||
|         } | ||||
|                 } | ||||
|                 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 ); | ||||
|         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" ); | ||||
|             } | ||||
|         } | ||||
|                 tokens.push_back( token ); | ||||
|  | ||||
|         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; | ||||
|             } | ||||
|         } | ||||
|         std::string separators; | ||||
|         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> | ||||
| @@ -894,21 +914,21 @@ namespace Clara { | ||||
|             return oss.str(); | ||||
|         } | ||||
|  | ||||
|         ConfigT parse( int argc, char const* const argv[] ) const { | ||||
|         ConfigT parse( std::vector<std::string> const& args ) const { | ||||
|             ConfigT config; | ||||
|             parseInto( argc, argv, config ); | ||||
|             parseInto( args, config ); | ||||
|             return config; | ||||
|         } | ||||
|  | ||||
|         std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { | ||||
|             std::string processName = argv[0]; | ||||
|         std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { | ||||
|             std::string processName = args[0]; | ||||
|             std::size_t lastSlash = processName.find_last_of( "/\\" ); | ||||
|             if( lastSlash != std::string::npos ) | ||||
|                 processName = processName.substr( lastSlash+1 ); | ||||
|             m_boundProcessName.set( config, processName ); | ||||
|             std::vector<Parser::Token> tokens; | ||||
|             Parser parser; | ||||
|             parser.parseIntoTokens( argc, argv, tokens ); | ||||
|             parser.parseIntoTokens( args, tokens ); | ||||
|             return populate( tokens, config ); | ||||
|         } | ||||
|  | ||||
| @@ -939,7 +959,7 @@ namespace Clara { | ||||
|                                     arg.boundField.set( config, tokens[++i].data ); | ||||
|                             } | ||||
|                             else { | ||||
|                                 arg.boundField.setFlag( config ); | ||||
|                                 arg.boundField.set( config, "true" ); | ||||
|                             } | ||||
|                             break; | ||||
|                         } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ CATCH_REGISTER_TAG_ALIAS( "[@tricky]", "[tricky]~[.]" ) | ||||
| template<size_t size> | ||||
| void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { | ||||
|     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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash