clara.hpp 43 KB

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