embedded v1.0-develop.2 of Clara, which addresses / prefixed options, which should impact non-windows platforms

See #1054
This commit is contained in:
Phil Nash 2017-10-21 09:16:38 +02:00
parent 5af918eefd
commit 75a77b6f8c
2 changed files with 45 additions and 17 deletions

View File

@ -1,4 +1,4 @@
// v1.0 // v1.0-develop.2
// See https://github.com/philsquared/Clara // See https://github.com/philsquared/Clara
#ifndef CATCH_CLARA_HPP_INCLUDED #ifndef CATCH_CLARA_HPP_INCLUDED
@ -409,6 +409,14 @@ namespace detail {
std::string token; std::string token;
}; };
inline auto isOptPrefix( char c ) -> bool {
return c == '-'
#ifdef CATCH_PLATFORM_WINDOWS
|| c == '/'
#endif
;
}
// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
class TokenStream { class TokenStream {
using Iterator = std::vector<std::string>::const_iterator; using Iterator = std::vector<std::string>::const_iterator;
@ -425,7 +433,7 @@ namespace detail {
if( it != itEnd ) { if( it != itEnd ) {
auto const &next = *it; auto const &next = *it;
if( next[0] == '-' || next[0] == '/' ) { if( isOptPrefix( next[0] ) ) {
auto delimiterPos = next.find_first_of( " :=" ); auto delimiterPos = next.find_first_of( " :=" );
if( delimiterPos != std::string::npos ) { if( delimiterPos != std::string::npos ) {
m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
@ -915,9 +923,11 @@ namespace detail {
}; };
inline auto normaliseOpt( std::string const &optName ) -> std::string { inline auto normaliseOpt( std::string const &optName ) -> std::string {
#ifdef CATCH_PLATFORM_WINDOWS
if( optName[0] == '/' ) if( optName[0] == '/' )
return "-" + optName.substr( 1 ); return "-" + optName.substr( 1 );
else else
#endif
return optName; return optName;
} }
@ -958,11 +968,7 @@ namespace detail {
} }
auto isMatch( std::string const &optToken ) const -> bool { auto isMatch( std::string const &optToken ) const -> bool {
#ifdef CATCH_PLATFORM_WINDOWS
auto normalisedToken = normaliseOpt( optToken ); auto normalisedToken = normaliseOpt( optToken );
#else
auto const &normalisedToken = optToken;
#endif
for( auto const &name : m_optNames ) { for( auto const &name : m_optNames ) {
if( normaliseOpt( name ) == normalisedToken ) if( normaliseOpt( name ) == normalisedToken )
return true; return true;
@ -1012,8 +1018,13 @@ namespace detail {
for( auto const &name : m_optNames ) { for( auto const &name : m_optNames ) {
if( name.empty() ) if( name.empty() )
return Result::logicError( "Option name cannot be empty" ); return Result::logicError( "Option name cannot be empty" );
#ifdef CATCH_PLATFORM_WINDOWS
if( name[0] != '-' && name[0] != '/' ) if( name[0] != '-' && name[0] != '/' )
return Result::logicError( "Option name must begin with '-' or '/'" ); return Result::logicError( "Option name must begin with '-' or '/'" );
#else
if( name[0] != '-' )
return Result::logicError( "Option name must begin with '-'" );
#endif
} }
return ParserRefImpl::validate(); return ParserRefImpl::validate();
} }

37
third_party/clara.hpp vendored
View File

@ -1,4 +1,4 @@
// v1.0 // v1.0-develop.2
// See https://github.com/philsquared/Clara // See https://github.com/philsquared/Clara
#ifndef CLARA_HPP_INCLUDED #ifndef CLARA_HPP_INCLUDED
@ -409,6 +409,14 @@ namespace detail {
std::string token; std::string token;
}; };
inline auto isOptPrefix( char c ) -> bool {
return c == '-'
#ifdef CLARA_PLATFORM_WINDOWS
|| c == '/'
#endif
;
}
// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
class TokenStream { class TokenStream {
using Iterator = std::vector<std::string>::const_iterator; using Iterator = std::vector<std::string>::const_iterator;
@ -425,7 +433,7 @@ namespace detail {
if( it != itEnd ) { if( it != itEnd ) {
auto const &next = *it; auto const &next = *it;
if( next[0] == '-' || next[0] == '/' ) { if( isOptPrefix( next[0] ) ) {
auto delimiterPos = next.find_first_of( " :=" ); auto delimiterPos = next.find_first_of( " :=" );
if( delimiterPos != std::string::npos ) { if( delimiterPos != std::string::npos ) {
m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
@ -915,9 +923,11 @@ namespace detail {
}; };
inline auto normaliseOpt( std::string const &optName ) -> std::string { inline auto normaliseOpt( std::string const &optName ) -> std::string {
#ifdef CLARA_PLATFORM_WINDOWS
if( optName[0] == '/' ) if( optName[0] == '/' )
return "-" + optName.substr( 1 ); return "-" + optName.substr( 1 );
else else
#endif
return optName; return optName;
} }
@ -958,11 +968,7 @@ namespace detail {
} }
auto isMatch( std::string const &optToken ) const -> bool { auto isMatch( std::string const &optToken ) const -> bool {
#ifdef CLARA_PLATFORM_WINDOWS
auto normalisedToken = normaliseOpt( optToken ); auto normalisedToken = normaliseOpt( optToken );
#else
auto const &normalisedToken = optToken;
#endif
for( auto const &name : m_optNames ) { for( auto const &name : m_optNames ) {
if( normaliseOpt( name ) == normalisedToken ) if( normaliseOpt( name ) == normalisedToken )
return true; return true;
@ -1012,8 +1018,13 @@ namespace detail {
for( auto const &name : m_optNames ) { for( auto const &name : m_optNames ) {
if( name.empty() ) if( name.empty() )
return Result::logicError( "Option name cannot be empty" ); return Result::logicError( "Option name cannot be empty" );
#ifdef CLARA_PLATFORM_WINDOWS
if( name[0] != '-' && name[0] != '/' ) if( name[0] != '-' && name[0] != '/' )
return Result::logicError( "Option name must begin with '-' or '/'" ); return Result::logicError( "Option name must begin with '-' or '/'" );
#else
if( name[0] != '-' )
return Result::logicError( "Option name must begin with '-'" );
#endif
} }
return ParserRefImpl::validate(); return ParserRefImpl::validate();
} }
@ -1142,10 +1153,15 @@ namespace detail {
size_t count = 0; size_t count = 0;
}; };
const size_t totalParsers = m_options.size() + m_args.size(); const size_t totalParsers = m_options.size() + m_args.size();
ParserInfo parseInfos[totalParsers]; assert( totalParsers < 512 );
// ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
ParserInfo parseInfos[512];
{
size_t i = 0; size_t i = 0;
for( auto const& opt : m_options ) parseInfos[i++].parser = &opt; for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
for( auto const& arg : m_args ) parseInfos[i++].parser = &arg; for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
}
m_exeName.set( exeName ); m_exeName.set( exeName );
@ -1153,7 +1169,8 @@ namespace detail {
while( result.value().remainingTokens() ) { while( result.value().remainingTokens() ) {
bool tokenParsed = false; bool tokenParsed = false;
for( auto& parseInfo : parseInfos ) { for( size_t i = 0; i < totalParsers; ++i ) {
auto& parseInfo = parseInfos[i];
if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
if (!result) if (!result)