@@ -168,23 +168,6 @@ namespace po {
168
168
}
169
169
#endif // !PROGRAMOPTIONS_NO_COLORS
170
170
171
- #ifdef PROGRAMOPTIONS_SILENT
172
- inline std::ostream& err () {
173
- struct dummy_buf_t : public std ::streambuf {
174
- int overflow ( int c ) {
175
- return c;
176
- }
177
- };
178
- static dummy_buf_t dummy_buf;
179
- static std::ostream dummy_str{ &dummy_buf };
180
- return dummy_str;
181
- }
182
- #else // PROGRAMOPTIONS_SILENT
183
- inline std::ostream& err () {
184
- return std::cerr;
185
- }
186
- #endif // PROGRAMOPTIONS_SILENT
187
-
188
171
struct error_t {
189
172
friend std::ostream& operator <<( std::ostream& stream, error_t const & /* object */ ) { // -Wunused-parameter
190
173
return stream << red << " error: " ;
@@ -224,15 +207,6 @@ namespace po {
224
207
return { arg };
225
208
}
226
209
227
- template < typename arg_t >
228
- void error_nonoption_arguments ( arg_t const & arg ) {
229
- err () << error () << " non-option arguments not allowed" << ignoring ( arg );
230
- }
231
- template < typename arg_t >
232
- void error_unrecognized_option ( arg_t const & arg ) {
233
- err () << error () << " unrecognized option" << ignoring ( arg );
234
- }
235
-
236
210
// Compatibility stuff for the lack of C++14 support
237
211
template < typename T, typename ... args_t >
238
212
std::unique_ptr< T > make_unique ( args_t &&... args ) {
@@ -1654,6 +1628,37 @@ namespace po {
1654
1628
using options_t = std::unordered_map< std::string, option >;
1655
1629
options_t m_options;
1656
1630
char const * m_program_name = " " ;
1631
+ std::ostream* m_output_destination;
1632
+
1633
+ public:
1634
+ parser () {
1635
+ verbose ( std::cerr );
1636
+ }
1637
+
1638
+ void silent () {
1639
+ m_output_destination = nullptr ;
1640
+ }
1641
+ bool is_silent () const {
1642
+ return m_output_destination == nullptr ;
1643
+ }
1644
+ void verbose ( std::ostream& destination ) {
1645
+ m_output_destination = &destination;
1646
+ }
1647
+ bool is_verbose () const {
1648
+ return !is_silent ();
1649
+ }
1650
+
1651
+ private:
1652
+ template < typename arg_t >
1653
+ void error_nonoption_arguments ( arg_t const & arg ) {
1654
+ assert ( is_verbose () );
1655
+ *m_output_destination << error () << " non-option arguments not allowed" << ignoring ( arg );
1656
+ }
1657
+ template < typename arg_t >
1658
+ void error_unrecognized_option ( arg_t const & arg ) {
1659
+ assert ( is_verbose () );
1660
+ *m_output_destination << error () << " unrecognized option" << ignoring ( arg );
1661
+ }
1657
1662
1658
1663
options_t ::iterator find_abbreviation ( char value ) {
1659
1664
auto iter = m_options.begin ();
@@ -1664,16 +1669,18 @@ namespace po {
1664
1669
}
1665
1670
1666
1671
void check_spelling ( char short_option ) {
1672
+ assert ( is_verbose () );
1667
1673
if ( !std::isalpha ( short_option ) )
1668
1674
return ;
1669
1675
if ( std::islower ( short_option ) )
1670
1676
short_option = std::toupper ( short_option );
1671
1677
else // if( std::isupper( short_option ) )
1672
1678
short_option = std::tolower ( short_option );
1673
1679
if ( find_abbreviation ( short_option ) != m_options.end () )
1674
- err () << suggest ( std::string{ ' -' , short_option } );
1680
+ *m_output_destination << suggest ( std::string{ ' -' , short_option } );
1675
1681
}
1676
1682
void check_spelling ( char const * long_option ) {
1683
+ assert ( is_verbose () );
1677
1684
assert ( long_option[ 0 ] == ' -' && long_option[ 1 ] == ' -' && long_option[ 2 ] != ' \0 ' );
1678
1685
enum : std::size_t {
1679
1686
distance_cutoff = 4
@@ -1698,31 +1705,32 @@ namespace po {
1698
1705
}
1699
1706
}
1700
1707
if ( min_distance < distance_cutoff )
1701
- err () << suggest ( std::string ( " --" ) + nearest_option->first );
1708
+ *m_output_destination << suggest ( std::string ( " --" ) + nearest_option->first );
1702
1709
}
1703
1710
template < typename expression_t , typename ... args_t >
1704
1711
bool parse_argument ( options_t ::iterator option, expression_t const & expression, args_t &&... args ) const {
1705
1712
const error_code code = option->second .parse ( std::forward< args_t >( args )... );
1706
1713
if ( code == error_code::none )
1707
1714
return true ;
1708
- err () << error () << " option \' " ;
1709
- err () << blue << option->first ;
1710
- err () << " \' " ;
1711
- switch ( code ) {
1712
- case error_code::argument_expected:
1713
- case error_code::conversion_error:
1714
- err () << " expects an argument of type " << vt2str ( option->second .get_type () );
1715
- break ;
1716
- case error_code::no_argument_expected:
1717
- err () << " doesn't expect any arguments" ;
1718
- break ;
1719
- case error_code::out_of_range:
1720
- err () << " has an argument that caused an out of range error" ;
1721
- break ;
1722
- case error_code::none:
1723
- ;
1715
+ if ( is_verbose () ) {
1716
+ *m_output_destination << error () << " option \' " ;
1717
+ *m_output_destination << blue << option->first ;
1718
+ *m_output_destination << " \' " ;
1719
+ switch ( code ) {
1720
+ case error_code::argument_expected:
1721
+ case error_code::conversion_error:
1722
+ *m_output_destination << " expects an argument of type " << vt2str ( option->second .get_type () );
1723
+ break ;
1724
+ case error_code::no_argument_expected:
1725
+ *m_output_destination << " doesn't expect any arguments" ;
1726
+ break ;
1727
+ case error_code::out_of_range:
1728
+ *m_output_destination << " has an argument that caused an out of range error" ;
1729
+ default : // -Wswitch
1730
+ ;
1731
+ }
1732
+ *m_output_destination << ignoring ( expression ) << ' \n ' ;
1724
1733
}
1725
- err () << ignoring ( expression ) << ' \n ' ;
1726
1734
return false ;
1727
1735
}
1728
1736
bool dashed_non_option ( char * arg ) {
@@ -1752,7 +1760,12 @@ namespace po {
1752
1760
// -vdata
1753
1761
argument = &argv[ i ][ j ];
1754
1762
} else {
1755
- err () << error () << " unexpected character \' " << argv[ i ][ j ] << " \' " << ignoring ( argv[ i ] ) << suggest ( std::string{ &argv[ i ][ 0 ], &argv[ i ][ j ] } + " =" + std::string{ &argv[ i ][ j ] } ) << ' \n ' ;
1763
+ if ( is_verbose () )
1764
+ *m_output_destination
1765
+ << error ()
1766
+ << " unexpected character \' " << argv[ i ][ j ] << " \' "
1767
+ << ignoring ( argv[ i ] )
1768
+ << suggest ( std::string{ &argv[ i ][ 0 ], &argv[ i ][ j ] } + " =" + std::string{ &argv[ i ][ j ] } ) << ' \n ' ;
1756
1769
return false ;
1757
1770
}
1758
1771
return parse_argument ( option, std::move ( expression ), argument );
@@ -1762,7 +1775,8 @@ namespace po {
1762
1775
if ( !result ) {
1763
1776
good = false ;
1764
1777
error_nonoption_arguments ( arg );
1765
- err () << ' \n ' ;
1778
+ if ( is_verbose () )
1779
+ *m_output_destination << ' \n ' ;
1766
1780
}
1767
1781
return result;
1768
1782
}
@@ -1833,15 +1847,19 @@ namespace po {
1833
1847
for ( ; valid_designator_character ( *last ); ++last );
1834
1848
if ( first == last ) {
1835
1849
good = false ;
1836
- error_unrecognized_option ( argv[ i ] );
1837
- err () << ' \n ' ;
1850
+ if ( is_verbose () ) {
1851
+ error_unrecognized_option ( argv[ i ] );
1852
+ *m_output_destination << ' \n ' ;
1853
+ }
1838
1854
} else {
1839
1855
const auto opt = m_options.find ( std::string{ first, last } );
1840
1856
if ( opt == m_options.end () ) {
1841
1857
good = false ;
1842
- error_unrecognized_option ( argv[ i ] );
1843
- check_spelling ( argv[ i ] );
1844
- err () << ' \n ' ;
1858
+ if ( is_verbose () ) {
1859
+ error_unrecognized_option ( argv[ i ] );
1860
+ check_spelling ( argv[ i ] );
1861
+ *m_output_destination << ' \n ' ;
1862
+ }
1845
1863
} else {
1846
1864
good &= extract_argument ( opt, argc, argv, i, last - argv[ i ] );
1847
1865
}
@@ -1852,29 +1870,35 @@ namespace po {
1852
1870
const auto head = find_abbreviation ( argv[ i ][ 1 ] );
1853
1871
if ( head == m_options.end () ) {
1854
1872
good = false ;
1855
- error_unrecognized_option ( argv[ i ] );
1856
- check_spelling ( argv[ i ][ 1 ] );
1857
- err () << ' \n ' ;
1873
+ if ( is_verbose () ) {
1874
+ error_unrecognized_option ( argv[ i ] );
1875
+ check_spelling ( argv[ i ][ 1 ] );
1876
+ *m_output_destination << ' \n ' ;
1877
+ }
1858
1878
} else if ( head->second .get_type () == void_ ) {
1859
1879
// -fgh
1860
1880
char c;
1861
1881
for ( std::size_t j = 1 ; ( c = argv[ i ][ j ] ) != ' \0 ' ; ++j ) {
1862
1882
if ( !std::isprint ( c ) || c == ' -' ) {
1863
1883
good = false ;
1864
- err () << error () << " invalid character \' " << c << " \' " << ignoring ( &argv[ i ][ j ] ) << ' \n ' ;
1884
+ if ( is_verbose () )
1885
+ *m_output_destination << error () << " invalid character \' " << c << " \' " << ignoring ( &argv[ i ][ j ] ) << ' \n ' ;
1865
1886
break ;
1866
1887
}
1867
1888
const auto opt = find_abbreviation ( c );
1868
1889
if ( opt == m_options.end () ) {
1869
1890
good = false ;
1870
- error_unrecognized_option ( c );
1871
- check_spelling ( c );
1872
- err () << ' \n ' ;
1891
+ if ( is_verbose () ) {
1892
+ error_unrecognized_option ( c );
1893
+ check_spelling ( c );
1894
+ *m_output_destination << ' \n ' ;
1895
+ }
1873
1896
continue ;
1874
1897
}
1875
1898
if ( opt->second .get_type () != void_ ) {
1876
1899
good = false ;
1877
- err () << error () << " non-void options not allowed in option packs" << ignoring ( c ) << ' \n ' ;
1900
+ if ( is_verbose () )
1901
+ *m_output_destination << error () << " non-void options not allowed in option packs" << ignoring ( c ) << ' \n ' ;
1878
1902
continue ;
1879
1903
}
1880
1904
good &= parse_argument ( opt, c );
0 commit comments