diff --git a/src/catch2/internal/catch_clara.cpp b/src/catch2/internal/catch_clara.cpp index b4f5d054..68603923 100644 --- a/src/catch2/internal/catch_clara.cpp +++ b/src/catch2/internal/catch_clara.cpp @@ -37,6 +37,19 @@ namespace { return optName; } + static size_t find_first_separator(Catch::StringRef sr) { + auto is_separator = []( char c ) { + return c == ' ' || c == ':' || c == '='; + }; + size_t pos = 0; + while (pos < sr.size()) { + if (is_separator(sr[pos])) { return pos; } + ++pos; + } + + return Catch::StringRef::npos; + } + } // namespace namespace Catch { @@ -52,23 +65,23 @@ namespace Catch { } if ( it != itEnd ) { - auto const& next = *it; + StringRef next = *it; if ( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if ( delimiterPos != std::string::npos ) { + auto delimiterPos = find_first_separator(next); + if ( delimiterPos != StringRef::npos ) { m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); m_tokenBuffer.push_back( { TokenType::Argument, - next.substr( delimiterPos + 1 ) } ); + next.substr( delimiterPos + 1, next.size() ) } ); } else { if ( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; + // Combined short args, e.g. "-ab" for "-a -b" for ( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; m_tokenBuffer.push_back( - { TokenType::Option, opt } ); + { TokenType::Option, + next.substr( i, 1 ) } ); } } else { m_tokenBuffer.push_back( @@ -128,7 +141,7 @@ namespace Catch { size_t ParserBase::cardinality() const { return 1; } InternalParseResult ParserBase::parse( Args const& args ) const { - return parse( args.exeName(), TokenStream( args ) ); + return parse( static_cast(args.exeName()), TokenStream( args ) ); } ParseState::ParseState( ParseResultType type, @@ -166,7 +179,7 @@ namespace Catch { auto valueRef = static_cast(m_ref.get()); - auto result = valueRef->setValue(remainingTokens->token); + auto result = valueRef->setValue(static_cast(token.token)); if (!result) return Detail::InternalParseResult(result); else @@ -192,7 +205,7 @@ namespace Catch { return { oss.str(), m_description }; } - bool Opt::isMatch(std::string const& optToken) const { + bool Opt::isMatch(StringRef optToken) const { auto normalisedToken = normaliseOpt(optToken); for (auto const& name : m_optNames) { if (normaliseOpt(name) == normalisedToken) @@ -237,7 +250,7 @@ namespace Catch { return Detail::InternalParseResult::runtimeError( "Expected argument following " + token.token); - const auto result = valueRef->setValue(argToken.token); + const auto result = valueRef->setValue(static_cast(argToken.token)); if (!result) return Detail::InternalParseResult(result); if (result.value() == @@ -433,7 +446,7 @@ namespace Catch { Args::Args(int argc, char const* const* argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {} - Args::Args(std::initializer_list args) : + Args::Args(std::initializer_list args) : m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {} diff --git a/src/catch2/internal/catch_clara.hpp b/src/catch2/internal/catch_clara.hpp index a5c5e4e4..608f7274 100644 --- a/src/catch2/internal/catch_clara.hpp +++ b/src/catch2/internal/catch_clara.hpp @@ -102,17 +102,16 @@ namespace Catch { enum class TokenType { Option, Argument }; struct Token { TokenType type; - std::string token; + StringRef token; }; // Abstracts iterators into args as a stream of tokens, with option // arguments uniformly handled class TokenStream { - using Iterator = std::vector::const_iterator; + using Iterator = std::vector::const_iterator; Iterator it; Iterator itEnd; std::vector m_tokenBuffer; - void loadBuffer(); public: @@ -582,7 +581,7 @@ namespace Catch { Detail::HelpColumns getHelpColumns() const; - bool isMatch(std::string const& optToken) const; + bool isMatch(StringRef optToken) const; using ParserBase::parse; @@ -676,18 +675,20 @@ namespace Catch { Detail::TokenStream const& tokens) const override; }; - // Transport for raw args (copied from main args, or supplied via - // init list for testing) + /** + * Wrapper over argc + argv, assumes that the inputs outlive it + */ class Args { friend Detail::TokenStream; - std::string m_exeName; - std::vector m_args; + StringRef m_exeName; + std::vector m_args; public: Args(int argc, char const* const* argv); - Args(std::initializer_list args); + // Helper constructor for testing + Args(std::initializer_list args); - std::string const& exeName() const { return m_exeName; } + StringRef exeName() const { return m_exeName; } }; diff --git a/src/catch2/internal/catch_stringref.hpp b/src/catch2/internal/catch_stringref.hpp index 93f25171..4b9212bf 100644 --- a/src/catch2/internal/catch_stringref.hpp +++ b/src/catch2/internal/catch_stringref.hpp @@ -25,6 +25,8 @@ namespace Catch { using size_type = std::size_t; using const_iterator = const char*; + static constexpr size_type npos{ static_cast( -1 ) }; + private: static constexpr char const* const s_empty = "";