Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
clara.hpp
Go to the documentation of this file.
1// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// See https://github.com/philsquared/Clara for more details
7
8// Clara v1.1.5
9
10#ifndef CATCH_CLARA_HPP_INCLUDED
11#define CATCH_CLARA_HPP_INCLUDED
12
13#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
14#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
15#endif
16
17#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
18#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
19#endif
20
21#ifndef CLARA_CONFIG_OPTIONAL_TYPE
22#ifdef __has_include
23#if __has_include(<optional>) && __cplusplus >= 201703L
24#include <optional>
25#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
26#endif
27#endif
28#endif
29
30
31// ----------- #included from clara_textflow.hpp -----------
32
33// TextFlowCpp
34//
35// A single-header library for wrapping and laying out basic text, by Phil Nash
36//
37// Distributed under the Boost Software License, Version 1.0. (See accompanying
38// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
39//
40// This project is hosted at https://github.com/philsquared/textflowcpp
41
42#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
43#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
44
45#include <cassert>
46#include <ostream>
47#include <sstream>
48#include <vector>
49
50#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
51#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
52#endif
53
54
55namespace Catch {
56namespace clara {
57namespace TextFlow {
58
59inline auto isWhitespace(char c) -> bool {
60 static std::string chars = " \t\n\r";
61 return chars.find(c) != std::string::npos;
62}
63inline auto isBreakableBefore(char c) -> bool {
64 static std::string chars = "[({<|";
65 return chars.find(c) != std::string::npos;
66}
67inline auto isBreakableAfter(char c) -> bool {
68 static std::string chars = "])}>.,:;*+-=&/\\";
69 return chars.find(c) != std::string::npos;
70}
71
72class Columns;
73
74class Column {
75 std::vector<std::string> m_strings;
77 size_t m_indent = 0;
78 size_t m_initialIndent = std::string::npos;
79
80public:
81 class iterator {
82 friend Column;
83
84 Column const& m_column;
85 size_t m_stringIndex = 0;
86 size_t m_pos = 0;
87
88 size_t m_len = 0;
89 size_t m_end = 0;
90 bool m_suffix = false;
91
92 iterator(Column const& column, size_t stringIndex)
93 : m_column(column),
94 m_stringIndex(stringIndex) {}
95
96 auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
97
98 auto isBoundary(size_t at) const -> bool {
99 assert(at > 0);
100 assert(at <= line().size());
101
102 return at == line().size() ||
103 (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
104 isBreakableBefore(line()[at]) ||
105 isBreakableAfter(line()[at - 1]);
106 }
107
108 void calcLength() {
109 assert(m_stringIndex < m_column.m_strings.size());
110
111 m_suffix = false;
112 auto width = m_column.m_width - indent();
113 m_end = m_pos;
114 if (line()[m_pos] == '\n') {
115 ++m_end;
116 }
117 while (m_end < line().size() && line()[m_end] != '\n')
118 ++m_end;
119
120 if (m_end < m_pos + width) {
121 m_len = m_end - m_pos;
122 } else {
123 size_t len = width;
124 while (len > 0 && !isBoundary(m_pos + len))
125 --len;
126 while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
127 --len;
128
129 if (len > 0) {
130 m_len = len;
131 } else {
132 m_suffix = true;
133 m_len = width - 1;
134 }
135 }
136 }
137
138 auto indent() const -> size_t {
139 auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
140 return initial == std::string::npos ? m_column.m_indent : initial;
141 }
142
143 auto addIndentAndSuffix(std::string const &plain) const -> std::string {
144 return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
145 }
146
147 public:
148 using difference_type = std::ptrdiff_t;
149 using value_type = std::string;
150 using pointer = value_type * ;
152 using iterator_category = std::forward_iterator_tag;
153
154 explicit iterator(Column const& column) : m_column(column) {
155 assert(m_column.m_width > m_column.m_indent);
156 assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
157 calcLength();
158 if (m_len == 0)
159 m_stringIndex++; // Empty string
160 }
161
162 auto operator *() const -> std::string {
163 assert(m_stringIndex < m_column.m_strings.size());
164 assert(m_pos <= m_end);
165 return addIndentAndSuffix(line().substr(m_pos, m_len));
166 }
167
169 m_pos += m_len;
170 if (m_pos < line().size() && line()[m_pos] == '\n')
171 m_pos += 1;
172 else
173 while (m_pos < line().size() && isWhitespace(line()[m_pos]))
174 ++m_pos;
175
176 if (m_pos == line().size()) {
177 m_pos = 0;
178 ++m_stringIndex;
179 }
180 if (m_stringIndex < m_column.m_strings.size())
181 calcLength();
182 return *this;
183 }
184 auto operator ++(int) -> iterator {
185 iterator prev(*this);
186 operator++();
187 return prev;
188 }
189
190 auto operator ==(iterator const& other) const -> bool {
191 return
192 m_pos == other.m_pos &&
193 m_stringIndex == other.m_stringIndex &&
194 &m_column == &other.m_column;
195 }
196 auto operator !=(iterator const& other) const -> bool {
197 return !operator==(other);
198 }
199 };
201
202 explicit Column(std::string const& text) { m_strings.push_back(text); }
203
204 auto width(size_t newWidth) -> Column& {
205 assert(newWidth > 0);
206 m_width = newWidth;
207 return *this;
208 }
209 auto indent(size_t newIndent) -> Column& {
210 m_indent = newIndent;
211 return *this;
212 }
213 auto initialIndent(size_t newIndent) -> Column& {
214 m_initialIndent = newIndent;
215 return *this;
216 }
217
218 auto width() const -> size_t { return m_width; }
219 auto begin() const -> iterator { return iterator(*this); }
220 auto end() const -> iterator { return { *this, m_strings.size() }; }
221
222 inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
223 bool first = true;
224 for (auto line : col) {
225 if (first)
226 first = false;
227 else
228 os << "\n";
229 os << line;
230 }
231 return os;
232 }
233
234 auto operator + (Column const& other)->Columns;
235
236 auto toString() const -> std::string {
237 std::ostringstream oss;
238 oss << *this;
239 return oss.str();
240 }
241};
242
243class Spacer : public Column {
244
245public:
246 explicit Spacer(size_t spaceWidth) : Column("") {
247 width(spaceWidth);
248 }
249};
250
251class Columns {
252 std::vector<Column> m_columns;
253
254public:
255
256 class iterator {
257 friend Columns;
258 struct EndTag {};
259
260 std::vector<Column> const& m_columns;
261 std::vector<Column::iterator> m_iterators;
262 size_t m_activeIterators;
263
264 iterator(Columns const& columns, EndTag)
265 : m_columns(columns.m_columns),
266 m_activeIterators(0) {
267 m_iterators.reserve(m_columns.size());
268
269 for (auto const& col : m_columns)
270 m_iterators.push_back(col.end());
271 }
272
273 public:
274 using difference_type = std::ptrdiff_t;
275 using value_type = std::string;
276 using pointer = value_type * ;
278 using iterator_category = std::forward_iterator_tag;
279
280 explicit iterator(Columns const& columns)
281 : m_columns(columns.m_columns),
282 m_activeIterators(m_columns.size()) {
283 m_iterators.reserve(m_columns.size());
284
285 for (auto const& col : m_columns)
286 m_iterators.push_back(col.begin());
287 }
288
289 auto operator ==(iterator const& other) const -> bool {
290 return m_iterators == other.m_iterators;
291 }
292 auto operator !=(iterator const& other) const -> bool {
293 return m_iterators != other.m_iterators;
294 }
295 auto operator *() const -> std::string {
296 std::string row, padding;
297
298 for (size_t i = 0; i < m_columns.size(); ++i) {
299 auto width = m_columns[i].width();
300 if (m_iterators[i] != m_columns[i].end()) {
301 std::string col = *m_iterators[i];
302 row += padding + col;
303 if (col.size() < width)
304 padding = std::string(width - col.size(), ' ');
305 else
306 padding = "";
307 } else {
308 padding += std::string(width, ' ');
309 }
310 }
311 return row;
312 }
314 for (size_t i = 0; i < m_columns.size(); ++i) {
315 if (m_iterators[i] != m_columns[i].end())
316 ++m_iterators[i];
317 }
318 return *this;
319 }
320 auto operator ++(int) -> iterator {
321 iterator prev(*this);
322 operator++();
323 return prev;
324 }
325 };
327
328 auto begin() const -> iterator { return iterator(*this); }
329 auto end() const -> iterator { return { *this, iterator::EndTag() }; }
330
331 auto operator += (Column const& col) -> Columns& {
332 m_columns.push_back(col);
333 return *this;
334 }
335 auto operator + (Column const& col) -> Columns {
336 Columns combined = *this;
337 combined += col;
338 return combined;
339 }
340
341 inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
342
343 bool first = true;
344 for (auto line : cols) {
345 if (first)
346 first = false;
347 else
348 os << "\n";
349 os << line;
350 }
351 return os;
352 }
353
354 auto toString() const -> std::string {
355 std::ostringstream oss;
356 oss << *this;
357 return oss.str();
358 }
359};
360
361inline auto Column::operator + (Column const& other) -> Columns {
362 Columns cols;
363 cols += *this;
364 cols += other;
365 return cols;
366}
367}
368
369}
370}
371#endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
372
373// ----------- end of #include from clara_textflow.hpp -----------
374// ........... back in clara.hpp
375
376#include <cctype>
377#include <string>
378#include <memory>
379#include <set>
380#include <algorithm>
381
382#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
383#define CATCH_PLATFORM_WINDOWS
384#endif
385
386namespace Catch { namespace clara {
387namespace detail {
388
389 // Traits for extracting arg and return type of lambdas (for single argument lambdas)
390 template<typename L>
391 struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
392
393 template<typename ClassT, typename ReturnT, typename... Args>
394 struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
395 static const bool isValid = false;
396 };
397
398 template<typename ClassT, typename ReturnT, typename ArgT>
399 struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
400 static const bool isValid = true;
401 using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
402 using ReturnType = ReturnT;
403 };
404
405 class TokenStream;
406
407 // Transport for raw args (copied from main args, or supplied via init list for testing)
408 class Args {
409 friend TokenStream;
410 std::string m_exeName;
411 std::vector<std::string> m_args;
412
413 public:
414 Args( int argc, char const* const* argv )
415 : m_exeName(argv[0]),
416 m_args(argv + 1, argv + argc) {}
417
418 Args( std::initializer_list<std::string> args )
419 : m_exeName( *args.begin() ),
420 m_args( args.begin()+1, args.end() )
421 {}
422
423 auto exeName() const -> std::string {
424 return m_exeName;
425 }
426 };
427
428 // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
429 // may encode an option + its argument if the : or = form is used
430 enum class TokenType {
432 };
433 struct Token {
435 std::string token;
436 };
437
438 inline auto isOptPrefix( char c ) -> bool {
439 return c == '-'
440#ifdef CATCH_PLATFORM_WINDOWS
441 || c == '/'
442#endif
443 ;
444 }
445
446 // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
448 using Iterator = std::vector<std::string>::const_iterator;
449 Iterator it;
450 Iterator itEnd;
451 std::vector<Token> m_tokenBuffer;
452
453 void loadBuffer() {
454 m_tokenBuffer.resize( 0 );
455
456 // Skip any empty strings
457 while( it != itEnd && it->empty() )
458 ++it;
459
460 if( it != itEnd ) {
461 auto const &next = *it;
462 if( isOptPrefix( next[0] ) ) {
463 auto delimiterPos = next.find_first_of( " :=" );
464 if( delimiterPos != std::string::npos ) {
465 m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
466 m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
467 } else {
468 if( next[1] != '-' && next.size() > 2 ) {
469 std::string opt = "- ";
470 for( size_t i = 1; i < next.size(); ++i ) {
471 opt[1] = next[i];
472 m_tokenBuffer.push_back( { TokenType::Option, opt } );
473 }
474 } else {
475 m_tokenBuffer.push_back( { TokenType::Option, next } );
476 }
477 }
478 } else {
479 m_tokenBuffer.push_back( { TokenType::Argument, next } );
480 }
481 }
482 }
483
484 public:
485 explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
486
487 TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
488 loadBuffer();
489 }
490
491 explicit operator bool() const {
492 return !m_tokenBuffer.empty() || it != itEnd;
493 }
494
495 auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
496
497 auto operator*() const -> Token {
498 assert( !m_tokenBuffer.empty() );
499 return m_tokenBuffer.front();
500 }
501
502 auto operator->() const -> Token const * {
503 assert( !m_tokenBuffer.empty() );
504 return &m_tokenBuffer.front();
505 }
506
508 if( m_tokenBuffer.size() >= 2 ) {
509 m_tokenBuffer.erase( m_tokenBuffer.begin() );
510 } else {
511 if( it != itEnd )
512 ++it;
513 loadBuffer();
514 }
515 return *this;
516 }
517 };
518
519
521 public:
525
526 protected:
527 ResultBase( Type type ) : m_type( type ) {}
528 virtual ~ResultBase() = default;
529
530 virtual void enforceOk() const = 0;
531
533 };
534
535 template<typename T>
537 public:
538 auto value() const -> T const & {
539 enforceOk();
540 return m_value;
541 }
542
543 protected:
544 ResultValueBase( Type type ) : ResultBase( type ) {}
545
546 ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
547 if( m_type == ResultBase::Ok )
548 new( &m_value ) T( other.m_value );
549 }
550
552 new( &m_value ) T( value );
553 }
554
555 auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
556 if( m_type == ResultBase::Ok )
557 m_value.~T();
558 ResultBase::operator=(other);
559 if( m_type == ResultBase::Ok )
560 new( &m_value ) T( other.m_value );
561 return *this;
562 }
563
564 ~ResultValueBase() override {
565 if( m_type == Ok )
566 m_value.~T();
567 }
568
569 union {
571 };
572 };
573
574 template<>
575 class ResultValueBase<void> : public ResultBase {
576 protected:
578 };
579
580 template<typename T = void>
581 class BasicResult : public ResultValueBase<T> {
582 public:
583 template<typename U>
584 explicit BasicResult( BasicResult<U> const &other )
585 : ResultValueBase<T>( other.type() ),
587 {
588 assert( type() != ResultBase::Ok );
589 }
590
591 template<typename U>
592 static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
593 static auto ok() -> BasicResult { return { ResultBase::Ok }; }
594 static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
595 static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
596
597 explicit operator bool() const { return m_type == ResultBase::Ok; }
598 auto type() const -> ResultBase::Type { return m_type; }
599 auto errorMessage() const -> std::string { return m_errorMessage; }
600
601 protected:
602 void enforceOk() const override {
603
604 // Errors shouldn't reach this point, but if they do
605 // the actual error message will be in m_errorMessage
606 assert( m_type != ResultBase::LogicError );
607 assert( m_type != ResultBase::RuntimeError );
608 if( m_type != ResultBase::Ok )
609 std::abort();
610 }
611
612 std::string m_errorMessage; // Only populated if resultType is an error
613
614 BasicResult( ResultBase::Type type, std::string const &message )
615 : ResultValueBase<T>(type),
616 m_errorMessage(message)
617 {
618 assert( m_type != ResultBase::Ok );
619 }
620
621 using ResultValueBase<T>::ResultValueBase;
622 using ResultBase::m_type;
623 };
624
628
630 public:
631
633 : m_type(type),
634 m_remainingTokens( remainingTokens )
635 {}
636
637 auto type() const -> ParseResultType { return m_type; }
638 auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
639
640 private:
641 ParseResultType m_type;
642 TokenStream m_remainingTokens;
643 };
644
648
649 struct HelpColumns {
650 std::string left;
651 std::string right;
652 };
653
654 template<typename T>
655 inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
656 std::stringstream ss;
657 ss << source;
658 ss >> target;
659 if( ss.fail() )
660 return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
661 else
663 }
664 inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
665 target = source;
667 }
668 inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
669 std::string srcLC = source;
670 std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
671 if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
672 target = true;
673 else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
674 target = false;
675 else
676 return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
678 }
679#ifdef CLARA_CONFIG_OPTIONAL_TYPE
680 template<typename T>
681 inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
682 T temp;
683 auto result = convertInto( source, temp );
684 if( result )
685 target = std::move(temp);
686 return result;
687 }
688#endif // CLARA_CONFIG_OPTIONAL_TYPE
689
690 struct NonCopyable {
691 NonCopyable() = default;
692 NonCopyable( NonCopyable const & ) = delete;
693 NonCopyable( NonCopyable && ) = delete;
694 NonCopyable &operator=( NonCopyable const & ) = delete;
696 };
697
699 virtual ~BoundRef() = default;
700 virtual auto isContainer() const -> bool { return false; }
701 virtual auto isFlag() const -> bool { return false; }
702 };
704 virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
705 };
707 virtual auto setFlag( bool flag ) -> ParserResult = 0;
708 virtual auto isFlag() const -> bool { return true; }
709 };
710
711 template<typename T>
714
715 explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
716
717 auto setValue( std::string const &arg ) -> ParserResult override {
718 return convertInto( arg, m_ref );
719 }
720 };
721
722 template<typename T>
723 struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
724 std::vector<T> &m_ref;
725
726 explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
727
728 auto isContainer() const -> bool override { return true; }
729
730 auto setValue( std::string const &arg ) -> ParserResult override {
731 T temp;
732 auto result = convertInto( arg, temp );
733 if( result )
734 m_ref.push_back( temp );
735 return result;
736 }
737 };
738
740 bool &m_ref;
741
742 explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
743
744 auto setFlag( bool flag ) -> ParserResult override {
745 m_ref = flag;
747 }
748 };
749
750 template<typename ReturnType>
752 static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
753
754 template<typename L, typename ArgType>
755 static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
756 return lambda( arg );
757 }
758 };
759
760 template<>
761 struct LambdaInvoker<void> {
762 template<typename L, typename ArgType>
763 static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
764 lambda( arg );
766 }
767 };
768
769 template<typename ArgType, typename L>
770 inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
771 ArgType temp{};
772 auto result = convertInto( arg, temp );
773 return !result
774 ? result
776 }
777
778
779 template<typename L>
782
783 static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
784 explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
785
786 auto setValue( std::string const &arg ) -> ParserResult override {
787 return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
788 }
789 };
790
791 template<typename L>
794
795 static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
796 static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
797
798 explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
799
800 auto setFlag( bool flag ) -> ParserResult override {
802 }
803 };
804
806
807 struct Parser;
808
810 public:
811 virtual ~ParserBase() = default;
812 virtual auto validate() const -> Result { return Result::ok(); }
813 virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
814 virtual auto cardinality() const -> size_t { return 1; }
815
816 auto parse( Args const &args ) const -> InternalParseResult {
817 return parse( args.exeName(), TokenStream( args ) );
818 }
819 };
820
821 template<typename DerivedT>
823 public:
824 template<typename T>
825 auto operator|( T const &other ) const -> Parser;
826
827 template<typename T>
828 auto operator+( T const &other ) const -> Parser;
829 };
830
831 // Common code and state for Args and Opts
832 template<typename DerivedT>
833 class ParserRefImpl : public ComposableParserImpl<DerivedT> {
834 protected:
836 std::shared_ptr<BoundRef> m_ref;
837 std::string m_hint;
838 std::string m_description;
839
840 explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
841
842 public:
843 template<typename T>
844 ParserRefImpl( T &ref, std::string const &hint )
845 : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
846 m_hint( hint )
847 {}
848
849 template<typename LambdaT>
850 ParserRefImpl( LambdaT const &ref, std::string const &hint )
851 : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
852 m_hint(hint)
853 {}
854
855 auto operator()( std::string const &description ) -> DerivedT & {
856 m_description = description;
857 return static_cast<DerivedT &>( *this );
858 }
859
860 auto optional() -> DerivedT & {
862 return static_cast<DerivedT &>( *this );
863 };
864
865 auto required() -> DerivedT & {
867 return static_cast<DerivedT &>( *this );
868 };
869
870 auto isOptional() const -> bool {
872 }
873
874 auto cardinality() const -> size_t override {
875 if( m_ref->isContainer() )
876 return 0;
877 else
878 return 1;
879 }
880
881 auto hint() const -> std::string { return m_hint; }
882 };
883
884 class ExeName : public ComposableParserImpl<ExeName> {
885 std::shared_ptr<std::string> m_name;
886 std::shared_ptr<BoundValueRefBase> m_ref;
887
888 template<typename LambdaT>
889 static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
890 return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
891 }
892
893 public:
894 ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
895
896 explicit ExeName( std::string &ref ) : ExeName() {
897 m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
898 }
899
900 template<typename LambdaT>
901 explicit ExeName( LambdaT const& lambda ) : ExeName() {
902 m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
903 }
904
905 // The exe name is not parsed out of the normal tokens, but is handled specially
906 auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
908 }
909
910 auto name() const -> std::string { return *m_name; }
911 auto set( std::string const& newName ) -> ParserResult {
912
913 auto lastSlash = newName.find_last_of( "\\/" );
914 auto filename = ( lastSlash == std::string::npos )
915 ? newName
916 : newName.substr( lastSlash+1 );
917
918 *m_name = filename;
919 if( m_ref )
920 return m_ref->setValue( filename );
921 else
923 }
924 };
925
926 class Arg : public ParserRefImpl<Arg> {
927 public:
929
930 auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
931 auto validationResult = validate();
932 if( !validationResult )
933 return InternalParseResult( validationResult );
934
935 auto remainingTokens = tokens;
936 auto const &token = *remainingTokens;
937 if( token.type != TokenType::Argument )
938 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
939
940 assert( !m_ref->isFlag() );
941 auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
942
943 auto result = valueRef->setValue( remainingTokens->token );
944 if( !result )
945 return InternalParseResult( result );
946 else
947 return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
948 }
949 };
950
951 inline auto normaliseOpt( std::string const &optName ) -> std::string {
952#ifdef CATCH_PLATFORM_WINDOWS
953 if( optName[0] == '/' )
954 return "-" + optName.substr( 1 );
955 else
956#endif
957 return optName;
958 }
959
960 class Opt : public ParserRefImpl<Opt> {
961 protected:
962 std::vector<std::string> m_optNames;
963
964 public:
965 template<typename LambdaT>
966 explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
967
968 explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
969
970 template<typename LambdaT>
971 Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
972
973 template<typename T>
974 Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
975
976 auto operator[]( std::string const &optName ) -> Opt & {
977 m_optNames.push_back( optName );
978 return *this;
979 }
980
981 auto getHelpColumns() const -> std::vector<HelpColumns> {
982 std::ostringstream oss;
983 bool first = true;
984 for( auto const &opt : m_optNames ) {
985 if (first)
986 first = false;
987 else
988 oss << ", ";
989 oss << opt;
990 }
991 if( !m_hint.empty() )
992 oss << " <" << m_hint << ">";
993 return { { oss.str(), m_description } };
994 }
995
996 auto isMatch( std::string const &optToken ) const -> bool {
997 auto normalisedToken = normaliseOpt( optToken );
998 for( auto const &name : m_optNames ) {
999 if( normaliseOpt( name ) == normalisedToken )
1000 return true;
1001 }
1002 return false;
1003 }
1004
1005 using ParserBase::parse;
1006
1007 auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
1008 auto validationResult = validate();
1009 if( !validationResult )
1010 return InternalParseResult( validationResult );
1011
1012 auto remainingTokens = tokens;
1013 if( remainingTokens && remainingTokens->type == TokenType::Option ) {
1014 auto const &token = *remainingTokens;
1015 if( isMatch(token.token ) ) {
1016 if( m_ref->isFlag() ) {
1017 auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
1018 auto result = flagRef->setFlag( true );
1019 if( !result )
1020 return InternalParseResult( result );
1021 if( result.value() == ParseResultType::ShortCircuitAll )
1022 return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
1023 } else {
1024 auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
1025 ++remainingTokens;
1026 if( !remainingTokens )
1027 return InternalParseResult::runtimeError( "Expected argument following " + token.token );
1028 auto const &argToken = *remainingTokens;
1029 if( argToken.type != TokenType::Argument )
1030 return InternalParseResult::runtimeError( "Expected argument following " + token.token );
1031 auto result = valueRef->setValue( argToken.token );
1032 if( !result )
1033 return InternalParseResult( result );
1034 if( result.value() == ParseResultType::ShortCircuitAll )
1035 return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
1036 }
1037 return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
1038 }
1039 }
1040 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
1041 }
1042
1043 auto validate() const -> Result override {
1044 if( m_optNames.empty() )
1045 return Result::logicError( "No options supplied to Opt" );
1046 for( auto const &name : m_optNames ) {
1047 if( name.empty() )
1048 return Result::logicError( "Option name cannot be empty" );
1049#ifdef CATCH_PLATFORM_WINDOWS
1050 if( name[0] != '-' && name[0] != '/' )
1051 return Result::logicError( "Option name must begin with '-' or '/'" );
1052#else
1053 if( name[0] != '-' )
1054 return Result::logicError( "Option name must begin with '-'" );
1055#endif
1056 }
1057 return ParserRefImpl::validate();
1058 }
1059 };
1060
1061 struct Help : Opt {
1062 Help( bool &showHelpFlag )
1063 : Opt([&]( bool flag ) {
1064 showHelpFlag = flag;
1066 })
1067 {
1068 static_cast<Opt &>( *this )
1069 ("display usage information")
1070 ["-?"]["-h"]["--help"]
1071 .optional();
1072 }
1073 };
1074
1075
1077
1079 std::vector<Opt> m_options;
1080 std::vector<Arg> m_args;
1081
1082 auto operator|=( ExeName const &exeName ) -> Parser & {
1083 m_exeName = exeName;
1084 return *this;
1085 }
1086
1087 auto operator|=( Arg const &arg ) -> Parser & {
1088 m_args.push_back(arg);
1089 return *this;
1090 }
1091
1092 auto operator|=( Opt const &opt ) -> Parser & {
1093 m_options.push_back(opt);
1094 return *this;
1095 }
1096
1097 auto operator|=( Parser const &other ) -> Parser & {
1098 m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
1099 m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
1100 return *this;
1101 }
1102
1103 template<typename T>
1104 auto operator|( T const &other ) const -> Parser {
1105 return Parser( *this ) |= other;
1106 }
1107
1108 // Forward deprecated interface with '+' instead of '|'
1109 template<typename T>
1110 auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
1111 template<typename T>
1112 auto operator+( T const &other ) const -> Parser { return operator|( other ); }
1113
1114 auto getHelpColumns() const -> std::vector<HelpColumns> {
1115 std::vector<HelpColumns> cols;
1116 for (auto const &o : m_options) {
1117 auto childCols = o.getHelpColumns();
1118 cols.insert( cols.end(), childCols.begin(), childCols.end() );
1119 }
1120 return cols;
1121 }
1122
1123 void writeToStream( std::ostream &os ) const {
1124 if (!m_exeName.name().empty()) {
1125 os << "usage:\n" << " " << m_exeName.name() << " ";
1126 bool required = true, first = true;
1127 for( auto const &arg : m_args ) {
1128 if (first)
1129 first = false;
1130 else
1131 os << " ";
1132 if( arg.isOptional() && required ) {
1133 os << "[";
1134 required = false;
1135 }
1136 os << "<" << arg.hint() << ">";
1137 if( arg.cardinality() == 0 )
1138 os << " ... ";
1139 }
1140 if( !required )
1141 os << "]";
1142 if( !m_options.empty() )
1143 os << " options";
1144 os << "\n\nwhere options are:" << std::endl;
1145 }
1146
1147 auto rows = getHelpColumns();
1148 size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
1149 size_t optWidth = 0;
1150 for( auto const &cols : rows )
1151 optWidth = (std::max)(optWidth, cols.left.size() + 2);
1152
1153 optWidth = (std::min)(optWidth, consoleWidth/2);
1154
1155 for( auto const &cols : rows ) {
1156 auto row =
1157 TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
1158 TextFlow::Spacer(4) +
1159 TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
1160 os << row << std::endl;
1161 }
1162 }
1163
1164 friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
1165 parser.writeToStream( os );
1166 return os;
1167 }
1168
1169 auto validate() const -> Result override {
1170 for( auto const &opt : m_options ) {
1171 auto result = opt.validate();
1172 if( !result )
1173 return result;
1174 }
1175 for( auto const &arg : m_args ) {
1176 auto result = arg.validate();
1177 if( !result )
1178 return result;
1179 }
1180 return Result::ok();
1181 }
1182
1183 using ParserBase::parse;
1184
1185 auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
1186
1187 struct ParserInfo {
1188 ParserBase const* parser = nullptr;
1189 size_t count = 0;
1190 };
1191 const size_t totalParsers = m_options.size() + m_args.size();
1192 assert( totalParsers < 512 );
1193 // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
1194 ParserInfo parseInfos[512];
1195
1196 {
1197 size_t i = 0;
1198 for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
1199 for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
1200 }
1201
1202 m_exeName.set( exeName );
1203
1205 while( result.value().remainingTokens() ) {
1206 bool tokenParsed = false;
1207
1208 for( size_t i = 0; i < totalParsers; ++i ) {
1209 auto& parseInfo = parseInfos[i];
1210 if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
1211 result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
1212 if (!result)
1213 return result;
1214 if (result.value().type() != ParseResultType::NoMatch) {
1215 tokenParsed = true;
1216 ++parseInfo.count;
1217 break;
1218 }
1219 }
1220 }
1221
1222 if( result.value().type() == ParseResultType::ShortCircuitAll )
1223 return result;
1224 if( !tokenParsed )
1225 return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
1226 }
1227 // !TBD Check missing required options
1228 return result;
1229 }
1230 };
1231
1232 template<typename DerivedT>
1233 template<typename T>
1235 return Parser() | static_cast<DerivedT const &>( *this ) | other;
1236 }
1237} // namespace detail
1238
1239
1240// A Combined parser
1241using detail::Parser;
1242
1243// A parser for options
1244using detail::Opt;
1245
1246// A parser for arguments
1247using detail::Arg;
1248
1249// Wrapper for argc, argv from main()
1250using detail::Args;
1251
1252// Specifies the name of the executable
1253using detail::ExeName;
1254
1255// Convenience wrapper for option parser that specifies the help option
1256using detail::Help;
1257
1258// enum of result types from a parse
1260
1261// Result type for parser operation
1263
1264
1265}} // namespace Catch::clara
1266
1267
1268#endif // CATCH_CLARA_HPP_INCLUDED
std::string name
std::forward_iterator_tag iterator_category
Definition clara.hpp:152
auto operator!=(iterator const &other) const -> bool
Definition clara.hpp:196
auto operator*() const -> std::string
Definition clara.hpp:162
auto operator==(iterator const &other) const -> bool
Definition clara.hpp:190
auto width() const -> size_t
Definition clara.hpp:218
auto operator+(Column const &other) -> Columns
Definition clara.hpp:361
Column(std::string const &text)
Definition clara.hpp:202
auto indent(size_t newIndent) -> Column &
Definition clara.hpp:209
auto begin() const -> iterator
Definition clara.hpp:219
auto toString() const -> std::string
Definition clara.hpp:236
auto end() const -> iterator
Definition clara.hpp:220
auto width(size_t newWidth) -> Column &
Definition clara.hpp:204
friend std::ostream & operator<<(std::ostream &os, Column const &col)
Definition clara.hpp:222
auto initialIndent(size_t newIndent) -> Column &
Definition clara.hpp:213
iterator(Columns const &columns)
Definition clara.hpp:280
auto operator==(iterator const &other) const -> bool
Definition clara.hpp:289
auto operator*() const -> std::string
Definition clara.hpp:295
auto operator!=(iterator const &other) const -> bool
Definition clara.hpp:292
std::forward_iterator_tag iterator_category
Definition clara.hpp:278
auto operator+(Column const &col) -> Columns
Definition clara.hpp:335
auto toString() const -> std::string
Definition clara.hpp:354
auto end() const -> iterator
Definition clara.hpp:329
friend std::ostream & operator<<(std::ostream &os, Columns const &cols)
Definition clara.hpp:341
auto operator+=(Column const &col) -> Columns &
Definition clara.hpp:331
auto begin() const -> iterator
Definition clara.hpp:328
Spacer(size_t spaceWidth)
Definition clara.hpp:246
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override
Definition clara.hpp:930
Args(int argc, char const *const *argv)
Definition clara.hpp:414
auto exeName() const -> std::string
Definition clara.hpp:423
Args(std::initializer_list< std::string > args)
Definition clara.hpp:418
auto type() const -> ResultBase::Type
Definition clara.hpp:598
auto errorMessage() const -> std::string
Definition clara.hpp:599
BasicResult(ResultBase::Type type, std::string const &message)
Definition clara.hpp:614
BasicResult(BasicResult< U > const &other)
Definition clara.hpp:584
static auto runtimeError(std::string const &message) -> BasicResult
Definition clara.hpp:595
static auto ok() -> BasicResult
Definition clara.hpp:593
static auto logicError(std::string const &message) -> BasicResult
Definition clara.hpp:594
static auto ok(U const &value) -> BasicResult
Definition clara.hpp:592
void enforceOk() const override
Definition clara.hpp:602
auto operator|(T const &other) const -> Parser
Definition clara.hpp:1234
auto operator+(T const &other) const -> Parser
auto name() const -> std::string
Definition clara.hpp:910
auto set(std::string const &newName) -> ParserResult
Definition clara.hpp:911
ExeName(std::string &ref)
Definition clara.hpp:896
ExeName(LambdaT const &lambda)
Definition clara.hpp:901
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override
Definition clara.hpp:906
Opt(LambdaT const &ref)
Definition clara.hpp:966
std::vector< std::string > m_optNames
Definition clara.hpp:962
auto getHelpColumns() const -> std::vector< HelpColumns >
Definition clara.hpp:981
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override
Definition clara.hpp:1007
auto isMatch(std::string const &optToken) const -> bool
Definition clara.hpp:996
Opt(T &ref, std::string const &hint)
Definition clara.hpp:974
Opt(LambdaT const &ref, std::string const &hint)
Definition clara.hpp:971
auto operator[](std::string const &optName) -> Opt &
Definition clara.hpp:976
auto validate() const -> Result override
Definition clara.hpp:1043
auto type() const -> ParseResultType
Definition clara.hpp:637
ParseState(ParseResultType type, TokenStream const &remainingTokens)
Definition clara.hpp:632
auto remainingTokens() const -> TokenStream
Definition clara.hpp:638
auto parse(Args const &args) const -> InternalParseResult
Definition clara.hpp:816
virtual auto validate() const -> Result
Definition clara.hpp:812
virtual auto parse(std::string const &exeName, TokenStream const &tokens) const -> InternalParseResult=0
virtual auto cardinality() const -> size_t
Definition clara.hpp:814
auto required() -> DerivedT &
Definition clara.hpp:865
auto cardinality() const -> size_t override
Definition clara.hpp:874
ParserRefImpl(std::shared_ptr< BoundRef > const &ref)
Definition clara.hpp:840
auto optional() -> DerivedT &
Definition clara.hpp:860
ParserRefImpl(LambdaT const &ref, std::string const &hint)
Definition clara.hpp:850
ParserRefImpl(T &ref, std::string const &hint)
Definition clara.hpp:844
std::shared_ptr< BoundRef > m_ref
Definition clara.hpp:836
auto hint() const -> std::string
Definition clara.hpp:881
auto isOptional() const -> bool
Definition clara.hpp:870
auto operator()(std::string const &description) -> DerivedT &
Definition clara.hpp:855
virtual void enforceOk() const =0
auto operator=(ResultValueBase const &other) -> ResultValueBase &
Definition clara.hpp:555
ResultValueBase(Type, T const &value)
Definition clara.hpp:551
ResultValueBase(ResultValueBase const &other)
Definition clara.hpp:546
auto value() const -> T const &
Definition clara.hpp:538
auto operator->() const -> Token const *
Definition clara.hpp:502
TokenStream(Iterator it, Iterator itEnd)
Definition clara.hpp:487
auto count() const -> size_t
Definition clara.hpp:495
auto operator++() -> TokenStream &
Definition clara.hpp:507
TokenStream(Args const &args)
Definition clara.hpp:485
auto operator*() const -> Token
Definition clara.hpp:497
os_t os
int * count
char ** argv
#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH
Definition clara.hpp:14
#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
Definition clara.hpp:18
auto isBreakableBefore(char c) -> bool
Definition clara.hpp:63
auto isWhitespace(char c) -> bool
Definition clara.hpp:59
auto isBreakableAfter(char c) -> bool
Definition clara.hpp:67
auto convertInto(std::string const &source, T &target) -> ParserResult
Definition clara.hpp:655
BasicResult< ParseState > InternalParseResult
Definition clara.hpp:647
auto normaliseOpt(std::string const &optName) -> std::string
Definition clara.hpp:951
auto invokeLambda(L const &lambda, std::string const &arg) -> ParserResult
Definition clara.hpp:770
auto isOptPrefix(char c) -> bool
Definition clara.hpp:438
Definition name.hpp:106
#define value
Definition pkcs11.h:157
const CharType(& source)[N]
Definition pointer.h:1204
#define T(meth, val, expected)
auto setFlag(bool flag) -> ParserResult override
Definition clara.hpp:800
virtual auto setFlag(bool flag) -> ParserResult=0
virtual auto isFlag() const -> bool
Definition clara.hpp:708
auto setFlag(bool flag) -> ParserResult override
Definition clara.hpp:744
auto setValue(std::string const &arg) -> ParserResult override
Definition clara.hpp:786
virtual auto isContainer() const -> bool
Definition clara.hpp:700
virtual auto isFlag() const -> bool
Definition clara.hpp:701
auto setValue(std::string const &arg) -> ParserResult override
Definition clara.hpp:730
virtual auto setValue(std::string const &arg) -> ParserResult=0
auto setValue(std::string const &arg) -> ParserResult override
Definition clara.hpp:717
Help(bool &showHelpFlag)
Definition clara.hpp:1062
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult
Definition clara.hpp:763
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult
Definition clara.hpp:755
NonCopyable(NonCopyable &&)=delete
NonCopyable & operator=(NonCopyable &&)=delete
NonCopyable & operator=(NonCopyable const &)=delete
NonCopyable(NonCopyable const &)=delete
auto operator|=(ExeName const &exeName) -> Parser &
Definition clara.hpp:1082
std::vector< Opt > m_options
Definition clara.hpp:1079
auto operator|(T const &other) const -> Parser
Definition clara.hpp:1104
auto validate() const -> Result override
Definition clara.hpp:1169
void writeToStream(std::ostream &os) const
Definition clara.hpp:1123
auto operator|=(Opt const &opt) -> Parser &
Definition clara.hpp:1092
friend auto operator<<(std::ostream &os, Parser const &parser) -> std::ostream &
Definition clara.hpp:1164
std::vector< Arg > m_args
Definition clara.hpp:1080
auto operator|=(Arg const &arg) -> Parser &
Definition clara.hpp:1087
auto operator+(T const &other) const -> Parser
Definition clara.hpp:1112
auto operator|=(Parser const &other) -> Parser &
Definition clara.hpp:1097
auto parse(std::string const &exeName, TokenStream const &tokens) const -> InternalParseResult override
Definition clara.hpp:1185
auto getHelpColumns() const -> std::vector< HelpColumns >
Definition clara.hpp:1114
auto operator+=(T const &other) -> Parser &
Definition clara.hpp:1110
typename std::remove_const< typename std::remove_reference< ArgT >::type >::type ArgType
Definition clara.hpp:401
Definition dtoa.c:306
yh_object_type type
Definition yubihsm.h:672
size_t len