Blame third_party/clara.hpp

rpm-build a7f80b
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
rpm-build a7f80b
//
rpm-build a7f80b
// Distributed under the Boost Software License, Version 1.0. (See accompanying
rpm-build a7f80b
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
rpm-build a7f80b
//
rpm-build a7f80b
// See https://github.com/philsquared/Clara for more details
rpm-build a7f80b
rpm-build a7f80b
// Clara v1.1.4
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_HPP_INCLUDED
rpm-build a7f80b
#define CLARA_HPP_INCLUDED
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_CONFIG_CONSOLE_WIDTH
rpm-build a7f80b
#define CLARA_CONFIG_CONSOLE_WIDTH 80
rpm-build a7f80b
#endif
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
rpm-build a7f80b
#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
rpm-build a7f80b
#endif
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_CONFIG_OPTIONAL_TYPE
rpm-build a7f80b
#ifdef __has_include
rpm-build a7f80b
#if __has_include(<optional>) && __cplusplus >= 201703L
rpm-build a7f80b
#include <optional>
rpm-build a7f80b
#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
rpm-build a7f80b
#endif
rpm-build a7f80b
#endif
rpm-build a7f80b
#endif
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
// ----------- #included from clara_textflow.hpp -----------
rpm-build a7f80b
rpm-build a7f80b
// TextFlowCpp
rpm-build a7f80b
//
rpm-build a7f80b
// A single-header library for wrapping and laying out basic text, by Phil Nash
rpm-build a7f80b
//
rpm-build a7f80b
// This work is licensed under the BSD 2-Clause license.
rpm-build a7f80b
// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
rpm-build a7f80b
//
rpm-build a7f80b
// This project is hosted at https://github.com/philsquared/textflowcpp
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_TEXTFLOW_HPP_INCLUDED
rpm-build a7f80b
#define CLARA_TEXTFLOW_HPP_INCLUDED
rpm-build a7f80b
rpm-build a7f80b
#include <cassert>
rpm-build a7f80b
#include <ostream>
rpm-build a7f80b
#include <sstream>
rpm-build a7f80b
#include <vector>
rpm-build a7f80b
rpm-build a7f80b
#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
rpm-build a7f80b
#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
rpm-build a7f80b
#endif
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
namespace clara { namespace TextFlow {
rpm-build a7f80b
rpm-build a7f80b
    inline auto isWhitespace( char c ) -> bool {
rpm-build a7f80b
        static std::string chars = " \t\n\r";
rpm-build a7f80b
        return chars.find( c ) != std::string::npos;
rpm-build a7f80b
    }
rpm-build a7f80b
    inline auto isBreakableBefore( char c ) -> bool {
rpm-build a7f80b
        static std::string chars = "[({<|";
rpm-build a7f80b
        return chars.find( c ) != std::string::npos;
rpm-build a7f80b
    }
rpm-build a7f80b
    inline auto isBreakableAfter( char c ) -> bool {
rpm-build a7f80b
        static std::string chars = "])}>.,:;*+-=&/\\";
rpm-build a7f80b
        return chars.find( c ) != std::string::npos;
rpm-build a7f80b
    }
rpm-build a7f80b
rpm-build a7f80b
    class Columns;
rpm-build a7f80b
rpm-build a7f80b
    class Column {
rpm-build a7f80b
        std::vector<std::string> m_strings;
rpm-build a7f80b
        size_t m_width = CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
rpm-build a7f80b
        size_t m_indent = 0;
rpm-build a7f80b
        size_t m_initialIndent = std::string::npos;
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        class iterator {
rpm-build a7f80b
            friend Column;
rpm-build a7f80b
rpm-build a7f80b
            Column const& m_column;
rpm-build a7f80b
            size_t m_stringIndex = 0;
rpm-build a7f80b
            size_t m_pos = 0;
rpm-build a7f80b
rpm-build a7f80b
            size_t m_len = 0;
rpm-build a7f80b
            size_t m_end = 0;
rpm-build a7f80b
            bool m_suffix = false;
rpm-build a7f80b
rpm-build a7f80b
            iterator( Column const& column, size_t stringIndex )
rpm-build a7f80b
            :   m_column( column ),
rpm-build a7f80b
                m_stringIndex( stringIndex )
rpm-build a7f80b
            {}
rpm-build a7f80b
rpm-build a7f80b
            auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
rpm-build a7f80b
rpm-build a7f80b
            auto isBoundary( size_t at ) const -> bool {
rpm-build a7f80b
                assert( at > 0 );
rpm-build a7f80b
                assert( at <= line().size() );
rpm-build a7f80b
rpm-build a7f80b
                return at == line().size() ||
rpm-build a7f80b
                       ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
rpm-build a7f80b
                       isBreakableBefore( line()[at] ) ||
rpm-build a7f80b
                       isBreakableAfter( line()[at-1] );
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            void calcLength() {
rpm-build a7f80b
                assert( m_stringIndex < m_column.m_strings.size() );
rpm-build a7f80b
rpm-build a7f80b
                m_suffix = false;
rpm-build a7f80b
                auto width = m_column.m_width-indent();
rpm-build a7f80b
                m_end = m_pos;
rpm-build a7f80b
                while( m_end < line().size() && line()[m_end] != '\n' )
rpm-build a7f80b
                    ++m_end;
rpm-build a7f80b
rpm-build a7f80b
                if( m_end < m_pos + width ) {
rpm-build a7f80b
                    m_len = m_end - m_pos;
rpm-build a7f80b
                }
rpm-build a7f80b
                else {
rpm-build a7f80b
                    size_t len = width;
rpm-build a7f80b
                    while (len > 0 && !isBoundary(m_pos + len))
rpm-build a7f80b
                        --len;
rpm-build a7f80b
                    while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
rpm-build a7f80b
                        --len;
rpm-build a7f80b
rpm-build a7f80b
                    if (len > 0) {
rpm-build a7f80b
                        m_len = len;
rpm-build a7f80b
                    } else {
rpm-build a7f80b
                        m_suffix = true;
rpm-build a7f80b
                        m_len = width - 1;
rpm-build a7f80b
                    }
rpm-build a7f80b
                }
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto indent() const -> size_t {
rpm-build a7f80b
                auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
rpm-build a7f80b
                return initial == std::string::npos ? m_column.m_indent : initial;
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto addIndentAndSuffix(std::string const &plain) const -> std::string {
rpm-build a7f80b
                return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
        public:
rpm-build a7f80b
            explicit iterator( Column const& column ) : m_column( column ) {
rpm-build a7f80b
                assert( m_column.m_width > m_column.m_indent );
rpm-build a7f80b
                assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
rpm-build a7f80b
                calcLength();
rpm-build a7f80b
                if( m_len == 0 )
rpm-build a7f80b
                    m_stringIndex++; // Empty string
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto operator *() const -> std::string {
rpm-build a7f80b
                assert( m_stringIndex < m_column.m_strings.size() );
rpm-build a7f80b
                assert( m_pos <= m_end );
rpm-build a7f80b
                if( m_pos + m_column.m_width < m_end )
rpm-build a7f80b
                    return addIndentAndSuffix(line().substr(m_pos, m_len));
rpm-build a7f80b
                else
rpm-build a7f80b
                    return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto operator ++() -> iterator& {
rpm-build a7f80b
                m_pos += m_len;
rpm-build a7f80b
                if( m_pos < line().size() && line()[m_pos] == '\n' )
rpm-build a7f80b
                    m_pos += 1;
rpm-build a7f80b
                else
rpm-build a7f80b
                    while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
rpm-build a7f80b
                        ++m_pos;
rpm-build a7f80b
rpm-build a7f80b
                if( m_pos == line().size() ) {
rpm-build a7f80b
                    m_pos = 0;
rpm-build a7f80b
                    ++m_stringIndex;
rpm-build a7f80b
                }
rpm-build a7f80b
                if( m_stringIndex < m_column.m_strings.size() )
rpm-build a7f80b
                    calcLength();
rpm-build a7f80b
                return *this;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator ++(int) -> iterator {
rpm-build a7f80b
                iterator prev( *this );
rpm-build a7f80b
                operator++();
rpm-build a7f80b
                return prev;
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto operator ==( iterator const& other ) const -> bool {
rpm-build a7f80b
                return
rpm-build a7f80b
                    m_pos == other.m_pos &&
rpm-build a7f80b
                    m_stringIndex == other.m_stringIndex &&
rpm-build a7f80b
                    &m_column == &other.m_column;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator !=( iterator const& other ) const -> bool {
rpm-build a7f80b
                return !operator==( other );
rpm-build a7f80b
            }
rpm-build a7f80b
        };
rpm-build a7f80b
        using const_iterator = iterator;
rpm-build a7f80b
rpm-build a7f80b
        explicit Column( std::string const& text ) { m_strings.push_back( text ); }
rpm-build a7f80b
rpm-build a7f80b
        auto width( size_t newWidth ) -> Column& {
rpm-build a7f80b
            assert( newWidth > 0 );
rpm-build a7f80b
            m_width = newWidth;
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
        auto indent( size_t newIndent ) -> Column& {
rpm-build a7f80b
            m_indent = newIndent;
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
        auto initialIndent( size_t newIndent ) -> Column& {
rpm-build a7f80b
            m_initialIndent = newIndent;
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto width() const -> size_t { return m_width; }
rpm-build a7f80b
        auto begin() const -> iterator { return iterator( *this ); }
rpm-build a7f80b
        auto end() const -> iterator { return { *this, m_strings.size() }; }
rpm-build a7f80b
rpm-build a7f80b
        inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
rpm-build a7f80b
            bool first = true;
rpm-build a7f80b
            for( auto line : col ) {
rpm-build a7f80b
                if( first )
rpm-build a7f80b
                    first = false;
rpm-build a7f80b
                else
rpm-build a7f80b
                    os << "\n";
rpm-build a7f80b
                os <<  line;
rpm-build a7f80b
            }
rpm-build a7f80b
            return os;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator + ( Column const& other ) -> Columns;
rpm-build a7f80b
rpm-build a7f80b
        auto toString() const -> std::string {
rpm-build a7f80b
            std::ostringstream oss;
rpm-build a7f80b
            oss << *this;
rpm-build a7f80b
            return oss.str();
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class Spacer : public Column {
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        explicit Spacer( size_t spaceWidth ) : Column( "" ) {
rpm-build a7f80b
            width( spaceWidth );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class Columns {
rpm-build a7f80b
        std::vector<Column> m_columns;
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
rpm-build a7f80b
        class iterator {
rpm-build a7f80b
            friend Columns;
rpm-build a7f80b
            struct EndTag {};
rpm-build a7f80b
rpm-build a7f80b
            std::vector<Column> const& m_columns;
rpm-build a7f80b
            std::vector<Column::iterator> m_iterators;
rpm-build a7f80b
            size_t m_activeIterators;
rpm-build a7f80b
rpm-build a7f80b
            iterator( Columns const& columns, EndTag )
rpm-build a7f80b
            :   m_columns( columns.m_columns ),
rpm-build a7f80b
                m_activeIterators( 0 )
rpm-build a7f80b
            {
rpm-build a7f80b
                m_iterators.reserve( m_columns.size() );
rpm-build a7f80b
rpm-build a7f80b
                for( auto const& col : m_columns )
rpm-build a7f80b
                    m_iterators.push_back( col.end() );
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
        public:
rpm-build a7f80b
            explicit iterator( Columns const& columns )
rpm-build a7f80b
            :   m_columns( columns.m_columns ),
rpm-build a7f80b
                m_activeIterators( m_columns.size() )
rpm-build a7f80b
            {
rpm-build a7f80b
                m_iterators.reserve( m_columns.size() );
rpm-build a7f80b
rpm-build a7f80b
                for( auto const& col : m_columns )
rpm-build a7f80b
                    m_iterators.push_back( col.begin() );
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto operator ==( iterator const& other ) const -> bool {
rpm-build a7f80b
                return m_iterators == other.m_iterators;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator !=( iterator const& other ) const -> bool {
rpm-build a7f80b
                return m_iterators != other.m_iterators;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator *() const -> std::string {
rpm-build a7f80b
                std::string row, padding;
rpm-build a7f80b
rpm-build a7f80b
                for( size_t i = 0; i < m_columns.size(); ++i ) {
rpm-build a7f80b
                    auto width = m_columns[i].width();
rpm-build a7f80b
                    if( m_iterators[i] != m_columns[i].end() ) {
rpm-build a7f80b
                        std::string col = *m_iterators[i];
rpm-build a7f80b
                        row += padding + col;
rpm-build a7f80b
                        if( col.size() < width )
rpm-build a7f80b
                            padding = std::string( width - col.size(), ' ' );
rpm-build a7f80b
                        else
rpm-build a7f80b
                            padding = "";
rpm-build a7f80b
                    }
rpm-build a7f80b
                    else {
rpm-build a7f80b
                        padding += std::string( width, ' ' );
rpm-build a7f80b
                    }
rpm-build a7f80b
                }
rpm-build a7f80b
                return row;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator ++() -> iterator& {
rpm-build a7f80b
                for( size_t i = 0; i < m_columns.size(); ++i ) {
rpm-build a7f80b
                    if (m_iterators[i] != m_columns[i].end())
rpm-build a7f80b
                        ++m_iterators[i];
rpm-build a7f80b
                }
rpm-build a7f80b
                return *this;
rpm-build a7f80b
            }
rpm-build a7f80b
            auto operator ++(int) -> iterator {
rpm-build a7f80b
                iterator prev( *this );
rpm-build a7f80b
                operator++();
rpm-build a7f80b
                return prev;
rpm-build a7f80b
            }
rpm-build a7f80b
        };
rpm-build a7f80b
        using const_iterator = iterator;
rpm-build a7f80b
rpm-build a7f80b
        auto begin() const -> iterator { return iterator( *this ); }
rpm-build a7f80b
        auto end() const -> iterator { return { *this, iterator::EndTag() }; }
rpm-build a7f80b
rpm-build a7f80b
        auto operator += ( Column const& col ) -> Columns& {
rpm-build a7f80b
            m_columns.push_back( col );
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
        auto operator + ( Column const& col ) -> Columns {
rpm-build a7f80b
            Columns combined = *this;
rpm-build a7f80b
            combined += col;
rpm-build a7f80b
            return combined;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
rpm-build a7f80b
rpm-build a7f80b
            bool first = true;
rpm-build a7f80b
            for( auto line : cols ) {
rpm-build a7f80b
                if( first )
rpm-build a7f80b
                    first = false;
rpm-build a7f80b
                else
rpm-build a7f80b
                    os << "\n";
rpm-build a7f80b
                os << line;
rpm-build a7f80b
            }
rpm-build a7f80b
            return os;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto toString() const -> std::string {
rpm-build a7f80b
            std::ostringstream oss;
rpm-build a7f80b
            oss << *this;
rpm-build a7f80b
            return oss.str();
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    inline auto Column::operator + ( Column const& other ) -> Columns {
rpm-build a7f80b
        Columns cols;
rpm-build a7f80b
        cols += *this;
rpm-build a7f80b
        cols += other;
rpm-build a7f80b
        return cols;
rpm-build a7f80b
    }
rpm-build a7f80b
}} // namespace clara::TextFlow
rpm-build a7f80b
rpm-build a7f80b
#endif // CLARA_TEXTFLOW_HPP_INCLUDED
rpm-build a7f80b
rpm-build a7f80b
// ----------- end of #include from clara_textflow.hpp -----------
rpm-build a7f80b
// ........... back in clara.hpp
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
#include <memory>
rpm-build a7f80b
#include <set>
rpm-build a7f80b
#include <algorithm>
rpm-build a7f80b
rpm-build a7f80b
#if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
rpm-build a7f80b
#define CLARA_PLATFORM_WINDOWS
rpm-build a7f80b
#endif
rpm-build a7f80b
rpm-build a7f80b
namespace clara {
rpm-build a7f80b
namespace detail {
rpm-build a7f80b
rpm-build a7f80b
    // Traits for extracting arg and return type of lambdas (for single argument lambdas)
rpm-build a7f80b
    template<typename L>
rpm-build a7f80b
    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
rpm-build a7f80b
rpm-build a7f80b
    template<typename ClassT, typename ReturnT, typename... Args>
rpm-build a7f80b
    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
rpm-build a7f80b
        static const bool isValid = false;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename ClassT, typename ReturnT, typename ArgT>
rpm-build a7f80b
    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
rpm-build a7f80b
        static const bool isValid = true;
rpm-build a7f80b
        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
rpm-build a7f80b
        using ReturnType = ReturnT;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class TokenStream;
rpm-build a7f80b
rpm-build a7f80b
    // Transport for raw args (copied from main args, or supplied via init list for testing)
rpm-build a7f80b
    class Args {
rpm-build a7f80b
        friend TokenStream;
rpm-build a7f80b
        std::string m_exeName;
rpm-build a7f80b
        std::vector<std::string> m_args;
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        Args( int argc, char const* const* argv )
rpm-build a7f80b
            : m_exeName(argv[0]),
rpm-build a7f80b
              m_args(argv + 1, argv + argc) {}
rpm-build a7f80b
rpm-build a7f80b
        Args( std::initializer_list<std::string> args )
rpm-build a7f80b
        :   m_exeName( *args.begin() ),
rpm-build a7f80b
            m_args( args.begin()+1, args.end() )
rpm-build a7f80b
        {}
rpm-build a7f80b
rpm-build a7f80b
        auto exeName() const -> std::string {
rpm-build a7f80b
            return m_exeName;
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
rpm-build a7f80b
    // may encode an option + its argument if the : or = form is used
rpm-build a7f80b
    enum class TokenType {
rpm-build a7f80b
        Option, Argument
rpm-build a7f80b
    };
rpm-build a7f80b
    struct Token {
rpm-build a7f80b
        TokenType type;
rpm-build a7f80b
        std::string token;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    inline auto isOptPrefix( char c ) -> bool {
rpm-build a7f80b
        return c == '-'
rpm-build a7f80b
#ifdef CLARA_PLATFORM_WINDOWS
rpm-build a7f80b
            || c == '/'
rpm-build a7f80b
#endif
rpm-build a7f80b
        ;
rpm-build a7f80b
    }
rpm-build a7f80b
rpm-build a7f80b
    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
rpm-build a7f80b
    class TokenStream {
rpm-build a7f80b
        using Iterator = std::vector<std::string>::const_iterator;
rpm-build a7f80b
        Iterator it;
rpm-build a7f80b
        Iterator itEnd;
rpm-build a7f80b
        std::vector<Token> m_tokenBuffer;
rpm-build a7f80b
rpm-build a7f80b
        void loadBuffer() {
rpm-build a7f80b
            m_tokenBuffer.resize( 0 );
rpm-build a7f80b
rpm-build a7f80b
            // Skip any empty strings
rpm-build a7f80b
            while( it != itEnd && it->empty() )
rpm-build a7f80b
                ++it;
rpm-build a7f80b
rpm-build a7f80b
            if( it != itEnd ) {
rpm-build a7f80b
                auto const &next = *it;
rpm-build a7f80b
                if( isOptPrefix( next[0] ) ) {
rpm-build a7f80b
                    auto delimiterPos = next.find_first_of( " :=" );
rpm-build a7f80b
                    if( delimiterPos != std::string::npos ) {
rpm-build a7f80b
                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
rpm-build a7f80b
                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
rpm-build a7f80b
                    } else {
rpm-build a7f80b
                        if( next[1] != '-' && next.size() > 2 ) {
rpm-build a7f80b
                            std::string opt = "- ";
rpm-build a7f80b
                            for( size_t i = 1; i < next.size(); ++i ) {
rpm-build a7f80b
                                opt[1] = next[i];
rpm-build a7f80b
                                m_tokenBuffer.push_back( { TokenType::Option, opt } );
rpm-build a7f80b
                            }
rpm-build a7f80b
                        } else {
rpm-build a7f80b
                            m_tokenBuffer.push_back( { TokenType::Option, next } );
rpm-build a7f80b
                        }
rpm-build a7f80b
                    }
rpm-build a7f80b
                } else {
rpm-build a7f80b
                    m_tokenBuffer.push_back( { TokenType::Argument, next } );
rpm-build a7f80b
                }
rpm-build a7f80b
            }
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
rpm-build a7f80b
rpm-build a7f80b
        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
rpm-build a7f80b
            loadBuffer();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        explicit operator bool() const {
rpm-build a7f80b
            return !m_tokenBuffer.empty() || it != itEnd;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
rpm-build a7f80b
rpm-build a7f80b
        auto operator*() const -> Token {
rpm-build a7f80b
            assert( !m_tokenBuffer.empty() );
rpm-build a7f80b
            return m_tokenBuffer.front();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator->() const -> Token const * {
rpm-build a7f80b
            assert( !m_tokenBuffer.empty() );
rpm-build a7f80b
            return &m_tokenBuffer.front();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator++() -> TokenStream & {
rpm-build a7f80b
            if( m_tokenBuffer.size() >= 2 ) {
rpm-build a7f80b
                m_tokenBuffer.erase( m_tokenBuffer.begin() );
rpm-build a7f80b
            } else {
rpm-build a7f80b
                if( it != itEnd )
rpm-build a7f80b
                    ++it;
rpm-build a7f80b
                loadBuffer();
rpm-build a7f80b
            }
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
    class ResultBase {
rpm-build a7f80b
    public:
rpm-build a7f80b
        enum Type {
rpm-build a7f80b
            Ok, LogicError, RuntimeError
rpm-build a7f80b
        };
rpm-build a7f80b
rpm-build a7f80b
    protected:
rpm-build a7f80b
        ResultBase( Type type ) : m_type( type ) {}
rpm-build a7f80b
        virtual ~ResultBase() = default;
rpm-build a7f80b
rpm-build a7f80b
        virtual void enforceOk() const = 0;
rpm-build a7f80b
rpm-build a7f80b
        Type m_type;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    class ResultValueBase : public ResultBase {
rpm-build a7f80b
    public:
rpm-build a7f80b
        auto value() const -> T const & {
rpm-build a7f80b
            enforceOk();
rpm-build a7f80b
            return m_value;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
    protected:
rpm-build a7f80b
        ResultValueBase( Type type ) : ResultBase( type ) {}
rpm-build a7f80b
rpm-build a7f80b
        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
rpm-build a7f80b
            if( m_type == ResultBase::Ok )
rpm-build a7f80b
                new( &m_value ) T( other.m_value );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
rpm-build a7f80b
            new( &m_value ) T( value );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
rpm-build a7f80b
            if( m_type == ResultBase::Ok )
rpm-build a7f80b
                m_value.~T();
rpm-build a7f80b
            ResultBase::operator=(other);
rpm-build a7f80b
            if( m_type == ResultBase::Ok )
rpm-build a7f80b
                new( &m_value ) T( other.m_value );
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        ~ResultValueBase() override {
rpm-build a7f80b
            if( m_type == Ok )
rpm-build a7f80b
                m_value.~T();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        union {
rpm-build a7f80b
            T m_value;
rpm-build a7f80b
        };
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<>
rpm-build a7f80b
    class ResultValueBase<void> : public ResultBase {
rpm-build a7f80b
    protected:
rpm-build a7f80b
        using ResultBase::ResultBase;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename T = void>
rpm-build a7f80b
    class BasicResult : public ResultValueBase<T> {
rpm-build a7f80b
    public:
rpm-build a7f80b
        template<typename U>
rpm-build a7f80b
        explicit BasicResult( BasicResult<U> const &other )
rpm-build a7f80b
        :   ResultValueBase<T>( other.type() ),
rpm-build a7f80b
            m_errorMessage( other.errorMessage() )
rpm-build a7f80b
        {
rpm-build a7f80b
            assert( type() != ResultBase::Ok );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        template<typename U>
rpm-build a7f80b
        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
rpm-build a7f80b
        static auto ok() -> BasicResult { return { ResultBase::Ok }; }
rpm-build a7f80b
        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
rpm-build a7f80b
        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
rpm-build a7f80b
rpm-build a7f80b
        explicit operator bool() const { return m_type == ResultBase::Ok; }
rpm-build a7f80b
        auto type() const -> ResultBase::Type { return m_type; }
rpm-build a7f80b
        auto errorMessage() const -> std::string { return m_errorMessage; }
rpm-build a7f80b
rpm-build a7f80b
    protected:
rpm-build a7f80b
        void enforceOk() const override {
rpm-build a7f80b
rpm-build a7f80b
            // Errors shouldn't reach this point, but if they do
rpm-build a7f80b
            // the actual error message will be in m_errorMessage
rpm-build a7f80b
            assert( m_type != ResultBase::LogicError );
rpm-build a7f80b
            assert( m_type != ResultBase::RuntimeError );
rpm-build a7f80b
            if( m_type != ResultBase::Ok )
rpm-build a7f80b
                std::abort();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        std::string m_errorMessage; // Only populated if resultType is an error
rpm-build a7f80b
rpm-build a7f80b
        BasicResult( ResultBase::Type type, std::string const &message )
rpm-build a7f80b
        :   ResultValueBase<T>(type),
rpm-build a7f80b
            m_errorMessage(message)
rpm-build a7f80b
        {
rpm-build a7f80b
            assert( m_type != ResultBase::Ok );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        using ResultValueBase<T>::ResultValueBase;
rpm-build a7f80b
        using ResultBase::m_type;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    enum class ParseResultType {
rpm-build a7f80b
        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class ParseState {
rpm-build a7f80b
    public:
rpm-build a7f80b
rpm-build a7f80b
        ParseState( ParseResultType type, TokenStream const &remainingTokens )
rpm-build a7f80b
        : m_type(type),
rpm-build a7f80b
          m_remainingTokens( remainingTokens )
rpm-build a7f80b
        {}
rpm-build a7f80b
rpm-build a7f80b
        auto type() const -> ParseResultType { return m_type; }
rpm-build a7f80b
        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
rpm-build a7f80b
rpm-build a7f80b
    private:
rpm-build a7f80b
        ParseResultType m_type;
rpm-build a7f80b
        TokenStream m_remainingTokens;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    using Result = BasicResult<void>;
rpm-build a7f80b
    using ParserResult = BasicResult<ParseResultType>;
rpm-build a7f80b
    using InternalParseResult = BasicResult<ParseState>;
rpm-build a7f80b
rpm-build a7f80b
    struct HelpColumns {
rpm-build a7f80b
        std::string left;
rpm-build a7f80b
        std::string right;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
rpm-build a7f80b
        std::stringstream ss;
rpm-build a7f80b
        ss << source;
rpm-build a7f80b
        ss >> target;
rpm-build a7f80b
        if( ss.fail() )
rpm-build a7f80b
            return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
rpm-build a7f80b
        else
rpm-build a7f80b
            return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
    }
rpm-build a7f80b
    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
rpm-build a7f80b
        target = source;
rpm-build a7f80b
        return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
    }
rpm-build a7f80b
    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
rpm-build a7f80b
        std::string srcLC = source;
rpm-build a7f80b
        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
rpm-build a7f80b
        if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
rpm-build a7f80b
            target = true;
rpm-build a7f80b
        else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
rpm-build a7f80b
            target = false;
rpm-build a7f80b
        else
rpm-build a7f80b
            return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
rpm-build a7f80b
        return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
    }
rpm-build a7f80b
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
rpm-build a7f80b
        T temp;
rpm-build a7f80b
        auto result = convertInto( source, temp );
rpm-build a7f80b
        if( result )
rpm-build a7f80b
            target = std::move(temp);
rpm-build a7f80b
        return result;
rpm-build a7f80b
    }
rpm-build a7f80b
#endif // CLARA_CONFIG_OPTIONAL_TYPE
rpm-build a7f80b
rpm-build a7f80b
    struct NonCopyable {
rpm-build a7f80b
        NonCopyable() = default;
rpm-build a7f80b
        NonCopyable( NonCopyable const & ) = delete;
rpm-build a7f80b
        NonCopyable( NonCopyable && ) = delete;
rpm-build a7f80b
        NonCopyable &operator=( NonCopyable const & ) = delete;
rpm-build a7f80b
        NonCopyable &operator=( NonCopyable && ) = delete;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    struct BoundRef : NonCopyable {
rpm-build a7f80b
        virtual ~BoundRef() = default;
rpm-build a7f80b
        virtual auto isContainer() const -> bool { return false; }
rpm-build a7f80b
        virtual auto isFlag() const -> bool { return false; }
rpm-build a7f80b
    };
rpm-build a7f80b
    struct BoundValueRefBase : BoundRef {
rpm-build a7f80b
        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
rpm-build a7f80b
    };
rpm-build a7f80b
    struct BoundFlagRefBase : BoundRef {
rpm-build a7f80b
        virtual auto setFlag( bool flag ) -> ParserResult = 0;
rpm-build a7f80b
        virtual auto isFlag() const -> bool { return true; }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    struct BoundValueRef : BoundValueRefBase {
rpm-build a7f80b
        T &m_ref;
rpm-build a7f80b
rpm-build a7f80b
        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto setValue( std::string const &arg ) -> ParserResult override {
rpm-build a7f80b
            return convertInto( arg, m_ref );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
rpm-build a7f80b
        std::vector<T> &m_ref;
rpm-build a7f80b
rpm-build a7f80b
        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto isContainer() const -> bool override { return true; }
rpm-build a7f80b
rpm-build a7f80b
        auto setValue( std::string const &arg ) -> ParserResult override {
rpm-build a7f80b
            T temp;
rpm-build a7f80b
            auto result = convertInto( arg, temp );
rpm-build a7f80b
            if( result )
rpm-build a7f80b
                m_ref.push_back( temp );
rpm-build a7f80b
            return result;
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    struct BoundFlagRef : BoundFlagRefBase {
rpm-build a7f80b
        bool &m_ref;
rpm-build a7f80b
rpm-build a7f80b
        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto setFlag( bool flag ) -> ParserResult override {
rpm-build a7f80b
            m_ref = flag;
rpm-build a7f80b
            return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename ReturnType>
rpm-build a7f80b
    struct LambdaInvoker {
rpm-build a7f80b
        static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
rpm-build a7f80b
rpm-build a7f80b
        template<typename L, typename ArgType>
rpm-build a7f80b
        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
rpm-build a7f80b
            return lambda( arg );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<>
rpm-build a7f80b
    struct LambdaInvoker<void> {
rpm-build a7f80b
        template<typename L, typename ArgType>
rpm-build a7f80b
        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
rpm-build a7f80b
            lambda( arg );
rpm-build a7f80b
            return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename ArgType, typename L>
rpm-build a7f80b
    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
rpm-build a7f80b
        ArgType temp{};
rpm-build a7f80b
        auto result = convertInto( arg, temp );
rpm-build a7f80b
        return !result
rpm-build a7f80b
           ? result
rpm-build a7f80b
           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
rpm-build a7f80b
    }
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
    template<typename L>
rpm-build a7f80b
    struct BoundLambda : BoundValueRefBase {
rpm-build a7f80b
        L m_lambda;
rpm-build a7f80b
rpm-build a7f80b
        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
rpm-build a7f80b
        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto setValue( std::string const &arg ) -> ParserResult override {
rpm-build a7f80b
            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename L>
rpm-build a7f80b
    struct BoundFlagLambda : BoundFlagRefBase {
rpm-build a7f80b
        L m_lambda;
rpm-build a7f80b
rpm-build a7f80b
        static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
rpm-build a7f80b
        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
rpm-build a7f80b
rpm-build a7f80b
        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto setFlag( bool flag ) -> ParserResult override {
rpm-build a7f80b
            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    enum class Optionality { Optional, Required };
rpm-build a7f80b
rpm-build a7f80b
    struct Parser;
rpm-build a7f80b
rpm-build a7f80b
    class ParserBase {
rpm-build a7f80b
    public:
rpm-build a7f80b
        virtual ~ParserBase() = default;
rpm-build a7f80b
        virtual auto validate() const -> Result { return Result::ok(); }
rpm-build a7f80b
        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;
rpm-build a7f80b
        virtual auto cardinality() const -> size_t { return 1; }
rpm-build a7f80b
rpm-build a7f80b
        auto parse( Args const &args ) const -> InternalParseResult {
rpm-build a7f80b
            return parse( args.exeName(), TokenStream( args ) );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename DerivedT>
rpm-build a7f80b
    class ComposableParserImpl : public ParserBase {
rpm-build a7f80b
    public:
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        auto operator|( T const &other ) const -> Parser;
rpm-build a7f80b
rpm-build a7f80b
		template<typename T>
rpm-build a7f80b
        auto operator+( T const &other ) const -> Parser;
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    // Common code and state for Args and Opts
rpm-build a7f80b
    template<typename DerivedT>
rpm-build a7f80b
    class ParserRefImpl : public ComposableParserImpl<DerivedT> {
rpm-build a7f80b
    protected:
rpm-build a7f80b
        Optionality m_optionality = Optionality::Optional;
rpm-build a7f80b
        std::shared_ptr<BoundRef> m_ref;
rpm-build a7f80b
        std::string m_hint;
rpm-build a7f80b
        std::string m_description;
rpm-build a7f80b
rpm-build a7f80b
        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        ParserRefImpl( T &ref, std::string const &hint )
rpm-build a7f80b
        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
rpm-build a7f80b
            m_hint( hint )
rpm-build a7f80b
        {}
rpm-build a7f80b
rpm-build a7f80b
        template<typename LambdaT>
rpm-build a7f80b
        ParserRefImpl( LambdaT const &ref, std::string const &hint )
rpm-build a7f80b
        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
rpm-build a7f80b
            m_hint(hint)
rpm-build a7f80b
        {}
rpm-build a7f80b
rpm-build a7f80b
        auto operator()( std::string const &description ) -> DerivedT & {
rpm-build a7f80b
            m_description = description;
rpm-build a7f80b
            return static_cast<DerivedT &>( *this );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto optional() -> DerivedT & {
rpm-build a7f80b
            m_optionality = Optionality::Optional;
rpm-build a7f80b
            return static_cast<DerivedT &>( *this );
rpm-build a7f80b
        };
rpm-build a7f80b
rpm-build a7f80b
        auto required() -> DerivedT & {
rpm-build a7f80b
            m_optionality = Optionality::Required;
rpm-build a7f80b
            return static_cast<DerivedT &>( *this );
rpm-build a7f80b
        };
rpm-build a7f80b
rpm-build a7f80b
        auto isOptional() const -> bool {
rpm-build a7f80b
            return m_optionality == Optionality::Optional;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto cardinality() const -> size_t override {
rpm-build a7f80b
            if( m_ref->isContainer() )
rpm-build a7f80b
                return 0;
rpm-build a7f80b
            else
rpm-build a7f80b
                return 1;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto hint() const -> std::string { return m_hint; }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class ExeName : public ComposableParserImpl<ExeName> {
rpm-build a7f80b
        std::shared_ptr<std::string> m_name;
rpm-build a7f80b
        std::shared_ptr<BoundValueRefBase> m_ref;
rpm-build a7f80b
rpm-build a7f80b
        template<typename LambdaT>
rpm-build a7f80b
        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
rpm-build a7f80b
            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
rpm-build a7f80b
rpm-build a7f80b
        explicit ExeName( std::string &ref ) : ExeName() {
rpm-build a7f80b
            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        template<typename LambdaT>
rpm-build a7f80b
        explicit ExeName( LambdaT const& lambda ) : ExeName() {
rpm-build a7f80b
            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        // The exe name is not parsed out of the normal tokens, but is handled specially
rpm-build a7f80b
        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
rpm-build a7f80b
            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto name() const -> std::string { return *m_name; }
rpm-build a7f80b
        auto set( std::string const& newName ) -> ParserResult {
rpm-build a7f80b
rpm-build a7f80b
            auto lastSlash = newName.find_last_of( "\\/" );
rpm-build a7f80b
            auto filename = ( lastSlash == std::string::npos )
rpm-build a7f80b
                    ? newName
rpm-build a7f80b
                    : newName.substr( lastSlash+1 );
rpm-build a7f80b
rpm-build a7f80b
            *m_name = filename;
rpm-build a7f80b
            if( m_ref )
rpm-build a7f80b
                return m_ref->setValue( filename );
rpm-build a7f80b
            else
rpm-build a7f80b
                return ParserResult::ok( ParseResultType::Matched );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    class Arg : public ParserRefImpl<Arg> {
rpm-build a7f80b
    public:
rpm-build a7f80b
        using ParserRefImpl::ParserRefImpl;
rpm-build a7f80b
rpm-build a7f80b
        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
rpm-build a7f80b
            auto validationResult = validate();
rpm-build a7f80b
            if( !validationResult )
rpm-build a7f80b
                return InternalParseResult( validationResult );
rpm-build a7f80b
rpm-build a7f80b
            auto remainingTokens = tokens;
rpm-build a7f80b
            auto const &token = *remainingTokens;
rpm-build a7f80b
            if( token.type != TokenType::Argument )
rpm-build a7f80b
                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
rpm-build a7f80b
rpm-build a7f80b
            assert( !m_ref->isFlag() );
rpm-build a7f80b
            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
rpm-build a7f80b
rpm-build a7f80b
            auto result = valueRef->setValue( remainingTokens->token );
rpm-build a7f80b
            if( !result )
rpm-build a7f80b
                return InternalParseResult( result );
rpm-build a7f80b
            else
rpm-build a7f80b
                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    inline auto normaliseOpt( std::string const &optName ) -> std::string {
rpm-build a7f80b
#ifdef CLARA_PLATFORM_WINDOWS
rpm-build a7f80b
        if( optName[0] == '/' )
rpm-build a7f80b
            return "-" + optName.substr( 1 );
rpm-build a7f80b
        else
rpm-build a7f80b
#endif
rpm-build a7f80b
            return optName;
rpm-build a7f80b
    }
rpm-build a7f80b
rpm-build a7f80b
    class Opt : public ParserRefImpl<Opt> {
rpm-build a7f80b
    protected:
rpm-build a7f80b
        std::vector<std::string> m_optNames;
rpm-build a7f80b
rpm-build a7f80b
    public:
rpm-build a7f80b
        template<typename LambdaT>
rpm-build a7f80b
        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
rpm-build a7f80b
rpm-build a7f80b
        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
rpm-build a7f80b
rpm-build a7f80b
        template<typename LambdaT>
rpm-build a7f80b
        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
rpm-build a7f80b
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
rpm-build a7f80b
rpm-build a7f80b
        auto operator[]( std::string const &optName ) -> Opt & {
rpm-build a7f80b
            m_optNames.push_back( optName );
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto getHelpColumns() const -> std::vector<HelpColumns> {
rpm-build a7f80b
            std::ostringstream oss;
rpm-build a7f80b
            bool first = true;
rpm-build a7f80b
            for( auto const &opt : m_optNames ) {
rpm-build a7f80b
                if (first)
rpm-build a7f80b
                    first = false;
rpm-build a7f80b
                else
rpm-build a7f80b
                    oss << ", ";
rpm-build a7f80b
                oss << opt;
rpm-build a7f80b
            }
rpm-build a7f80b
            if( !m_hint.empty() )
rpm-build a7f80b
                oss << " <" << m_hint << ">";
rpm-build a7f80b
            return { { oss.str(), m_description } };
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto isMatch( std::string const &optToken ) const -> bool {
rpm-build a7f80b
            auto normalisedToken = normaliseOpt( optToken );
rpm-build a7f80b
            for( auto const &name : m_optNames ) {
rpm-build a7f80b
                if( normaliseOpt( name ) == normalisedToken )
rpm-build a7f80b
                    return true;
rpm-build a7f80b
            }
rpm-build a7f80b
            return false;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        using ParserBase::parse;
rpm-build a7f80b
rpm-build a7f80b
        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
rpm-build a7f80b
            auto validationResult = validate();
rpm-build a7f80b
            if( !validationResult )
rpm-build a7f80b
                return InternalParseResult( validationResult );
rpm-build a7f80b
rpm-build a7f80b
            auto remainingTokens = tokens;
rpm-build a7f80b
            if( remainingTokens && remainingTokens->type == TokenType::Option ) {
rpm-build a7f80b
                auto const &token = *remainingTokens;
rpm-build a7f80b
                if( isMatch(token.token ) ) {
rpm-build a7f80b
                    if( m_ref->isFlag() ) {
rpm-build a7f80b
                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
rpm-build a7f80b
                        auto result = flagRef->setFlag( true );
rpm-build a7f80b
                        if( !result )
rpm-build a7f80b
                            return InternalParseResult( result );
rpm-build a7f80b
                        if( result.value() == ParseResultType::ShortCircuitAll )
rpm-build a7f80b
                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
rpm-build a7f80b
                    } else {
rpm-build a7f80b
                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
rpm-build a7f80b
                        ++remainingTokens;
rpm-build a7f80b
                        if( !remainingTokens )
rpm-build a7f80b
                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
rpm-build a7f80b
                        auto const &argToken = *remainingTokens;
rpm-build a7f80b
                        if( argToken.type != TokenType::Argument )
rpm-build a7f80b
                            return InternalParseResult::runtimeError( "Expected argument following " + token.token );
rpm-build a7f80b
                        auto result = valueRef->setValue( argToken.token );
rpm-build a7f80b
                        if( !result )
rpm-build a7f80b
                            return InternalParseResult( result );
rpm-build a7f80b
                        if( result.value() == ParseResultType::ShortCircuitAll )
rpm-build a7f80b
                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
rpm-build a7f80b
                    }
rpm-build a7f80b
                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
rpm-build a7f80b
                }
rpm-build a7f80b
            }
rpm-build a7f80b
            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto validate() const -> Result override {
rpm-build a7f80b
            if( m_optNames.empty() )
rpm-build a7f80b
                return Result::logicError( "No options supplied to Opt" );
rpm-build a7f80b
            for( auto const &name : m_optNames ) {
rpm-build a7f80b
                if( name.empty() )
rpm-build a7f80b
                    return Result::logicError( "Option name cannot be empty" );
rpm-build a7f80b
#ifdef CLARA_PLATFORM_WINDOWS
rpm-build a7f80b
                if( name[0] != '-' && name[0] != '/' )
rpm-build a7f80b
                    return Result::logicError( "Option name must begin with '-' or '/'" );
rpm-build a7f80b
#else
rpm-build a7f80b
                if( name[0] != '-' )
rpm-build a7f80b
                    return Result::logicError( "Option name must begin with '-'" );
rpm-build a7f80b
#endif
rpm-build a7f80b
            }
rpm-build a7f80b
            return ParserRefImpl::validate();
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    struct Help : Opt {
rpm-build a7f80b
        Help( bool &showHelpFlag )
rpm-build a7f80b
        :   Opt([&]( bool flag ) {
rpm-build a7f80b
                showHelpFlag = flag;
rpm-build a7f80b
                return ParserResult::ok( ParseResultType::ShortCircuitAll );
rpm-build a7f80b
            })
rpm-build a7f80b
        {
rpm-build a7f80b
            static_cast<Opt &>( *this )
rpm-build a7f80b
                    ("display usage information")
rpm-build a7f80b
                    ["-?"]["-h"]["--help"]
rpm-build a7f80b
                    .optional();
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
    struct Parser : ParserBase {
rpm-build a7f80b
rpm-build a7f80b
        mutable ExeName m_exeName;
rpm-build a7f80b
        std::vector<Opt> m_options;
rpm-build a7f80b
        std::vector<Arg> m_args;
rpm-build a7f80b
rpm-build a7f80b
        auto operator|=( ExeName const &exeName ) -> Parser & {
rpm-build a7f80b
            m_exeName = exeName;
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator|=( Arg const &arg ) -> Parser & {
rpm-build a7f80b
            m_args.push_back(arg);
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator|=( Opt const &opt ) -> Parser & {
rpm-build a7f80b
            m_options.push_back(opt);
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto operator|=( Parser const &other ) -> Parser & {
rpm-build a7f80b
            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
rpm-build a7f80b
            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
rpm-build a7f80b
            return *this;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        auto operator|( T const &other ) const -> Parser {
rpm-build a7f80b
            return Parser( *this ) |= other;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        // Forward deprecated interface with '+' instead of '|'
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
rpm-build a7f80b
        template<typename T>
rpm-build a7f80b
        auto operator+( T const &other ) const -> Parser { return operator|( other ); }
rpm-build a7f80b
rpm-build a7f80b
        auto getHelpColumns() const -> std::vector<HelpColumns> {
rpm-build a7f80b
            std::vector<HelpColumns> cols;
rpm-build a7f80b
            for (auto const &o : m_options) {
rpm-build a7f80b
                auto childCols = o.getHelpColumns();
rpm-build a7f80b
                cols.insert( cols.end(), childCols.begin(), childCols.end() );
rpm-build a7f80b
            }
rpm-build a7f80b
            return cols;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        void writeToStream( std::ostream &os ) const {
rpm-build a7f80b
            if (!m_exeName.name().empty()) {
rpm-build a7f80b
                os << "usage:\n" << "  " << m_exeName.name() << " ";
rpm-build a7f80b
                bool required = true, first = true;
rpm-build a7f80b
                for( auto const &arg : m_args ) {
rpm-build a7f80b
                    if (first)
rpm-build a7f80b
                        first = false;
rpm-build a7f80b
                    else
rpm-build a7f80b
                        os << " ";
rpm-build a7f80b
                    if( arg.isOptional() && required ) {
rpm-build a7f80b
                        os << "[";
rpm-build a7f80b
                        required = false;
rpm-build a7f80b
                    }
rpm-build a7f80b
                    os << "<" << arg.hint() << ">";
rpm-build a7f80b
                    if( arg.cardinality() == 0 )
rpm-build a7f80b
                        os << " ... ";
rpm-build a7f80b
                }
rpm-build a7f80b
                if( !required )
rpm-build a7f80b
                    os << "]";
rpm-build a7f80b
                if( !m_options.empty() )
rpm-build a7f80b
                    os << " options";
rpm-build a7f80b
                os << "\n\nwhere options are:" << std::endl;
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            auto rows = getHelpColumns();
rpm-build a7f80b
            size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
rpm-build a7f80b
            size_t optWidth = 0;
rpm-build a7f80b
            for( auto const &cols : rows )
rpm-build a7f80b
                optWidth = (std::max)(optWidth, cols.left.size() + 2);
rpm-build a7f80b
rpm-build a7f80b
            optWidth = (std::min)(optWidth, consoleWidth/2);
rpm-build a7f80b
rpm-build a7f80b
            for( auto const &cols : rows ) {
rpm-build a7f80b
                auto row =
rpm-build a7f80b
                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
rpm-build a7f80b
                        TextFlow::Spacer(4) +
rpm-build a7f80b
                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
rpm-build a7f80b
                os << row << std::endl;
rpm-build a7f80b
            }
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
rpm-build a7f80b
            parser.writeToStream( os );
rpm-build a7f80b
            return os;
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        auto validate() const -> Result override {
rpm-build a7f80b
            for( auto const &opt : m_options ) {
rpm-build a7f80b
                auto result = opt.validate();
rpm-build a7f80b
                if( !result )
rpm-build a7f80b
                    return result;
rpm-build a7f80b
            }
rpm-build a7f80b
            for( auto const &arg : m_args ) {
rpm-build a7f80b
                auto result = arg.validate();
rpm-build a7f80b
                if( !result )
rpm-build a7f80b
                    return result;
rpm-build a7f80b
            }
rpm-build a7f80b
            return Result::ok();
rpm-build a7f80b
        }
rpm-build a7f80b
rpm-build a7f80b
        using ParserBase::parse;
rpm-build a7f80b
rpm-build a7f80b
        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
rpm-build a7f80b
rpm-build a7f80b
            struct ParserInfo {
rpm-build a7f80b
                ParserBase const* parser = nullptr;
rpm-build a7f80b
                size_t count = 0;
rpm-build a7f80b
            };
rpm-build a7f80b
            const size_t totalParsers = m_options.size() + m_args.size();
rpm-build a7f80b
            assert( totalParsers < 512 );
rpm-build a7f80b
            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
rpm-build a7f80b
            ParserInfo parseInfos[512];
rpm-build a7f80b
rpm-build a7f80b
            {
rpm-build a7f80b
                size_t i = 0;
rpm-build a7f80b
                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
rpm-build a7f80b
                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
rpm-build a7f80b
            }
rpm-build a7f80b
rpm-build a7f80b
            m_exeName.set( exeName );
rpm-build a7f80b
rpm-build a7f80b
            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
rpm-build a7f80b
            while( result.value().remainingTokens() ) {
rpm-build a7f80b
                bool tokenParsed = false;
rpm-build a7f80b
rpm-build a7f80b
                for( size_t i = 0; i < totalParsers; ++i ) {
rpm-build a7f80b
                    auto&  parseInfo = parseInfos[i];
rpm-build a7f80b
                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
rpm-build a7f80b
                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
rpm-build a7f80b
                        if (!result)
rpm-build a7f80b
                            return result;
rpm-build a7f80b
                        if (result.value().type() != ParseResultType::NoMatch) {
rpm-build a7f80b
                            tokenParsed = true;
rpm-build a7f80b
                            ++parseInfo.count;
rpm-build a7f80b
                            break;
rpm-build a7f80b
                        }
rpm-build a7f80b
                    }
rpm-build a7f80b
                }
rpm-build a7f80b
rpm-build a7f80b
                if( result.value().type() == ParseResultType::ShortCircuitAll )
rpm-build a7f80b
                    return result;
rpm-build a7f80b
                if( !tokenParsed )
rpm-build a7f80b
                    return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
rpm-build a7f80b
            }
rpm-build a7f80b
            // !TBD Check missing required options
rpm-build a7f80b
            return result;
rpm-build a7f80b
        }
rpm-build a7f80b
    };
rpm-build a7f80b
rpm-build a7f80b
    template<typename DerivedT>
rpm-build a7f80b
    template<typename T>
rpm-build a7f80b
    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
rpm-build a7f80b
        return Parser() | static_cast<DerivedT const &>( *this ) | other;
rpm-build a7f80b
    }
rpm-build a7f80b
} // namespace detail
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
// A Combined parser
rpm-build a7f80b
using detail::Parser;
rpm-build a7f80b
rpm-build a7f80b
// A parser for options
rpm-build a7f80b
using detail::Opt;
rpm-build a7f80b
rpm-build a7f80b
// A parser for arguments
rpm-build a7f80b
using detail::Arg;
rpm-build a7f80b
rpm-build a7f80b
// Wrapper for argc, argv from main()
rpm-build a7f80b
using detail::Args;
rpm-build a7f80b
rpm-build a7f80b
// Specifies the name of the executable
rpm-build a7f80b
using detail::ExeName;
rpm-build a7f80b
rpm-build a7f80b
// Convenience wrapper for option parser that specifies the help option
rpm-build a7f80b
using detail::Help;
rpm-build a7f80b
rpm-build a7f80b
// enum of result types from a parse
rpm-build a7f80b
using detail::ParseResultType;
rpm-build a7f80b
rpm-build a7f80b
// Result type for parser operation
rpm-build a7f80b
using detail::ParserResult;
rpm-build a7f80b
rpm-build a7f80b
rpm-build a7f80b
} // namespace clara
rpm-build a7f80b
rpm-build a7f80b
#endif // CLARA_HPP_INCLUDED