17static void printArgumentDescription( std::string
const &a_line, std::string
const &a_descriptor );
18static std::size_t maxPrintLineWidth = 120;
35 m_argumentType( a_argumentType ),
37 m_descriptor( a_descriptor ),
38 m_minimumNeeded( a_minimumNeeded ),
39 m_maximumNeeded( a_maximumNeeded ),
42 if( m_minimumNeeded < 0 )
throw std::runtime_error(
"ERROR 1000 in ArgumentBase::ArgumentBase: m_minimumNeeded must not be negative." );
43 if( m_maximumNeeded > -1 ) {
44 if( m_minimumNeeded > m_maximumNeeded )
45 throw std::runtime_error(
"ERROR 1010 in ArgumentBase::ArgumentBase: for argument '" + a_name +
"' m_maximumNeeded less than m_minimumNeeded." );
49 if( a_name[0] ==
'-' )
50 throw std::runtime_error(
"ERROR 1020 in ArgumentBase::ArgumentBase: positional argument name '" + a_name +
"' cannot start with a '-'." );
74 for(
auto iter = m_names.begin( ); iter != m_names.end( ); ++iter ) {
75 if( a_name == *iter )
return(
true );
91 throw Exception(
"Argument type for " +
name( ) +
" does not support calling value() method." );
93 if( a_index >= m_values.size( ) )
throw Exception(
"Index = " +
std::to_string( a_index ) +
" out-of-bounds for argument \"" +
name( ) +
"\"." );
95 return( m_values[a_index] );
104void ArgumentBase::addAlias( std::string
const &a_name ) {
107 if( m_names.size( ) > 0 )
throw std::runtime_error(
"ERROR 1100 in ArgumentBase::addAlias: cannot add a name to a positional argument." ); }
109 if( a_name[0] !=
'-' )
throw std::runtime_error(
"ERROR 1110 in ArgumentBase::addAlias: name '" + a_name +
"' not a valid optional name." );
112 if(
hasName( a_name ) )
return;
114 m_names.push_back( a_name );
135 if( maximumNeeded1 < 0 ) maximumNeeded1 = a_argc; }
137 if( ( maximumNeeded1 <
static_cast<int>(
counts( ) ) ) && ( maximumNeeded1 > -1 ) )
138 throw std::runtime_error(
"ERROR 1220 in ArgumentBase::parse: too many values for optional argument " +
name( ) +
" entered." );
142 for(
int index = 0; index < maximumNeeded1; ++index ) {
143 if( a_index == a_argc ) {
145 throw std::runtime_error(
"ERROR 1200 in ArgumentBase::parse: missing value for argument " +
name( ) +
"." );
149 m_values.push_back( a_argv[a_index] );
150 if( index > 0 ) ++m_counts;
168 std::string usageString;
171 if( a_requiredOption ) {
172 if( m_minimumNeeded != 0 )
return( usageString ); }
174 if( m_minimumNeeded == 0 )
return( usageString );
182 usageString +=
"[" +
name( ) +
value +
"]"; }
188 if( ( m_minimumNeeded != 1 ) || ( m_maximumNeeded != 1 ) )
192 return( usageString );
205 std::string name1 =
name( );
206 if( name1.size( ) < 32 ) name1.resize( 32,
' ' );
208 std::cout << a_indent << name1 <<
": number entered " <<
std::to_string( m_counts )
210 << printStatus2( ) << std::endl;
211 printStatus3( a_indent +
" " );
220std::string ArgumentBase::printStatus2( )
const {
232void ArgumentBase::printStatus3(
LUPI_maybeUnused std::string
const &a_indent )
const {
250 ArgumentBase( a_argumentType, a_name, a_descriptor, 0, -1 ),
251 m_default( a_default ) {
271 bool value1 = m_default;
272 if(
counts() == 0 ) value1 = !m_default;
274 if( value1 )
return(
": true" );
369 a_index =
values( ).size( );
370 if( a_index != 0 ) --a_index;
383 if(
counts( ) > 0 ) std::cout << a_indent <<
value( ) << std::endl;
412 for(
auto valueIterator =
values( ).begin( ); valueIterator !=
values( ).end( ); ++valueIterator ) {
413 std::cout << a_indent << *valueIterator << std::endl;
430Positional::Positional( std::string
const &a_name, std::string
const &a_descriptor,
int a_minimumNeeded,
int a_maximumNeeded ) :
442 for(
auto valueIterator =
values( ).begin( ); valueIterator !=
values( ).end( ); ++valueIterator ) {
443 std::cout << a_indent << *valueIterator << std::endl;
456 m_codeName(
FileInfo::basenameWithoutExtension( a_codeName ) ),
457 m_descriptor( a_descriptor ) {
467 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
468 delete *argumentIterator;
478void ArgumentParser::add2(
ArgumentBase *a_argumentBase ) {
481 for(
auto argumentIterator = m_arguments.rbegin( ); argumentIterator != m_arguments.rend( ); ++argumentIterator ) {
482 if( !(*argumentIterator)->isOptionalArgument( ) ) {
483 if( (*argumentIterator)->minimumNeeded( ) == (*argumentIterator)->maximumNeeded( ) )
break;
484 throw std::runtime_error(
"ERROR 1400 in ArgumentParser::add: request to add postional argument when prior postional argument '"
485 + (*argumentIterator)->name( ) +
"' takes a variable number of values." );
491 throw std::runtime_error(
"ERROR 1500 in ArgumentParser::add: name '" + a_argumentBase->
name( ) +
"' already present." );
493 m_arguments.push_back( a_argumentBase );
509 int a_minimumNeeded,
int a_maximumNeeded ) {
513 switch( a_argumentType ) {
515 argument =
new OptionTrue( a_name, a_descriptor );
518 argument =
new OptionFalse( a_name, a_descriptor );
524 argument =
new OptionStore( a_name, a_descriptor );
527 argument =
new OptionAppend( a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded );
530 argument =
new Positional( a_name, a_descriptor, a_minimumNeeded, a_maximumNeeded );
548 throw std::runtime_error(
"ERROR 1510 in ArgumentParser::addAlias: name '" + a_alias +
"' already present." );
550 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
551 if( (*argumentIterator)->hasName( a_name ) ) {
552 (*argumentIterator)->addAlias( a_alias );
556 throw std::runtime_error(
"ERROR 1520 in ArgumentParser::addAlias: no such argument named '" + a_name +
"'." );
581 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
582 if( (*argumentIterator)->hasName( a_name ) )
return( (*argumentIterator)->argumentType( ) !=
ArgumentType::Positional );
598 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
599 if( (*argumentIterator)->hasName( a_name ) )
return(
true );
614 for(
int iargc = 1; iargc < a_argc; ++iargc ) {
615 std::string arg( a_argv[iargc] );
617 if( ( arg ==
"-h" ) || ( arg ==
"--help" ) )
help( );
620 auto argumentIterator = m_arguments.begin( );
621 for( ; argumentIterator != m_arguments.end( ); ++argumentIterator ) {
622 if( !(*argumentIterator)->isOptionalArgument( ) )
break;
626 for( ; iargc < a_argc; ) {
627 std::string arg( a_argv[iargc] );
629 if( arg[0] ==
'-' ) {
630 auto argumentIterator2 = m_arguments.begin( );
631 for( ; argumentIterator2 != m_arguments.end( ); ++argumentIterator2 ) {
632 if( (*argumentIterator2)->hasName( arg ) )
break;
634 if( argumentIterator2 == m_arguments.end( ) )
throw std::runtime_error(
"ERROR 1600 in ArgumentParser::parse: invalid option '" + arg +
"'." );
635 iargc = (*argumentIterator2)->parse( *
this, iargc, a_argc, a_argv ); }
637 if( argumentIterator == m_arguments.end( ) )
638 throw std::runtime_error(
"ERROR 1610 in ArgumentParser::parse: additional positional argument found starting at index "
641 iargc = (*argumentIterator)->parse( *
this, iargc, a_argc, a_argv );
644 for( ; argumentIterator != m_arguments.end( ); ++argumentIterator ) {
645 if( !(*argumentIterator)->isOptionalArgument( ) )
break;
649 for(
auto argumentIterator2 = m_arguments.begin( ); argumentIterator2 != m_arguments.end( ); ++argumentIterator2 ) {
650 if(
static_cast<int>( (*argumentIterator2)->counts( ) ) < (*argumentIterator2)->minimumNeeded( ) ) {
651 std::string msg(
"arguments for" );
653 if( (*argumentIterator2)->isOptionalArgument( ) ) msg =
"number of option";
654 throw std::runtime_error(
"ERROR 1620 in ArgumentParser::parse: insufficient " + msg +
" '" + (*argumentIterator2)->name( )
655 +
"' entered. Range of " +
std::to_string( (*argumentIterator2)->minimumNeeded( ) ) +
" to "
656 +
std::to_string( (*argumentIterator2)->maximumNeeded( ) ) +
" required, "
657 +
std::to_string( (*argumentIterator2)->counts( ) ) +
" entered." );
661 if( a_printArguments ) {
663 for(
int i1 = 1; i1 < a_argc; i1++ ) std::cerr <<
" " << a_argv[i1];
664 std::cerr << std::endl;
676 if( m_descriptor !=
"" ) {
677 std::cout << std::endl <<
"Description:" << std::endl;
678 std::cout <<
" " << m_descriptor << std::endl;
681 bool printHeader =
true;
682 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
683 if( (*argumentIterator)->isOptionalArgument( ) )
continue;
685 if( printHeader ) std::cout << std::endl <<
"positional arguments:" << std::endl;
688 std::string line = (*argumentIterator)->name( );
689 if( ( (*argumentIterator)->minimumNeeded( ) != (*argumentIterator)->maximumNeeded( ) ) || ( (*argumentIterator)->maximumNeeded( ) != 1 ) )
690 line +=
" [" +
std::to_string( (*argumentIterator)->minimumNeeded( ) ) +
"," +
std::to_string( (*argumentIterator)->maximumNeeded( ) ) +
"]";
691 printArgumentDescription( line, (*argumentIterator)->descriptor( ) );
694 std::cout << std::endl <<
"optional arguments:" << std::endl;
695 std::cout <<
" -h, --help Show this help message and exit." << std::endl;
696 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
697 if( !(*argumentIterator)->isOptionalArgument( ) )
continue;
701 for(
auto namesIterator = (*argumentIterator)->names( ).begin( ); namesIterator != (*argumentIterator)->names( ).end( ); ++namesIterator ) {
702 line += sep + *namesIterator;
705 if( (*argumentIterator)->requiresAValue( ) ) line +=
" VALUE";
707 if( ( (*argumentIterator)->minimumNeeded( ) != (*argumentIterator)->maximumNeeded( ) ) || ( (*argumentIterator)->maximumNeeded( ) != 1 ) )
708 line +=
" [" +
std::to_string( (*argumentIterator)->minimumNeeded( ) ) +
"," +
std::to_string( (*argumentIterator)->maximumNeeded( ) ) +
"]";
710 printArgumentDescription( line, (*argumentIterator)->descriptor( ) );
713 exit( EXIT_SUCCESS );
722 std::string line(
"usage: " );
724 std::string indent(
"" );
725 indent.resize( line.size( ),
' ' );
728 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
729 if( (*argumentIterator)->isOptionalArgument( ) ) {
730 std::string optionUsage( (*argumentIterator)->usage(
counter == 0 ) );
732 if( ( line.size( ) + optionUsage.size( ) ) > maxPrintLineWidth ) {
733 std::cout << line << std::endl;
741 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
742 if( (*argumentIterator)->isOptionalArgument( ) )
continue;
743 std::string optionUsage( (*argumentIterator)->usage(
false ) );
745 if( ( line.size( ) + optionUsage.size( ) ) > maxPrintLineWidth ) {
746 std::cout << line << std::endl;
751 if( line.size( ) > indent.size( ) ) std::cout << line << std::endl;
752 std::cout << std::endl;
765 for(
auto argumentIterator = m_arguments.begin( ); argumentIterator != m_arguments.end( ); ++argumentIterator ) {
766 (*argumentIterator)->printStatus( a_indent );
778static void printArgumentDescription( std::string
const &a_line, std::string
const &a_descriptor ) {
780 std::string newLineSpaces =
" ";
781 auto size = newLineSpaces.size( );
782 auto maxDescriptionWidth = maxPrintLineWidth - size;
783 std::string line =
" " + a_line;
784 if( line.size( ) < size ) line.resize( size,
' ' );
786 if( line.size( ) > size ) std::cout << std::endl << newLineSpaces;
788 std::string descriptor = a_descriptor;
789 while( descriptor.size( ) > 0 ) {
790 auto length = descriptor.size( );
791 if( length > maxDescriptionWidth ) {
792 length = maxDescriptionWidth;
793 length = descriptor.rfind(
' ', length );
794 if( length == 0 ) length = descriptor.find(
' ', length );
797 std::cout <<
" " << descriptor.substr( 0, length ) << std::endl;
798 descriptor = descriptor.substr( length );
799 auto firstNotOf = descriptor.find_first_not_of(
" " );
800 if( firstNotOf != descriptor.npos ) descriptor = descriptor.substr( firstNotOf );
801 if( descriptor.size( ) > 0 ) std::cout << newLineSpaces;
virtual bool requiresAValue() const
std::vector< std::string > const & values() const
virtual bool isOptionalArgument() const
bool hasName(std::string const &a_name) const
virtual std::string const & value(std::size_t a_index=0) const
std::size_t counts() const
ArgumentBase(ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded, int a_maximumNeeded)
virtual int parse(ArgumentParser const &a_argumentParser, int a_index, int a_argc, char **a_argv)
std::string const & name() const
void printStatus(std::string a_indent) const
int maximumNeeded() const
std::string usage(bool a_requiredOption) const
virtual ~ArgumentBase()=0
virtual void printStatus(std::string a_indent) const
std::string const & codeName() const
T * add(std::string const &a_name, std::string const &a_descriptor, int a_minimumNeeded=1, int a_maximumNeeded=1)
ArgumentParser(std::string const &a_codeName, std::string const &a_descriptor="")
bool hasName(std::string const &a_name) const
void parse(int a_argc, char **a_argv, bool a_printArguments=true)
bool isOptionalArgument(std::string const &a_name) const
void addAlias(std::string const &a_name, std::string const &a_alias)
void printStatus3(std::string const &a_indent) const
OptionAppend(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string printStatus2() const
virtual ~OptionBoolean()=0
OptionBoolean(ArgumentType a_argumentType, std::string const &a_name, std::string const &a_descriptor, bool a_default)
OptionCounter(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string printStatus2() const
OptionFalse(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
std::string const & value(std::size_t a_index=0) const
OptionStore(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
void printStatus3(std::string const &a_indent) const
OptionTrue(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=0, int a_maximumNeeded=-1)
void printStatus3(std::string const &a_indent) const
Positional(std::string const &a_name, std::string const &a_descriptor="", int a_minimumNeeded=1, int a_maximumNeeded=1)
std::string basenameWithoutExtension(std::string const &a_path)
std::string to_string(G4FermiAtomicMass mass)