2015-09-06 20:19:09 +02:00
# include "./argumentparser.h"
# include "./commandlineutils.h"
# include "./failure.h"
2015-05-08 23:20:47 +02:00
2015-09-06 20:19:09 +02:00
# include "../conversion/stringconversion.h"
# include "../misc/random.h"
2015-04-22 18:36:40 +02:00
# include <algorithm>
# include <iostream>
2016-06-12 01:56:57 +02:00
# include <string>
2015-04-22 18:36:40 +02:00
# include <sstream>
2016-06-12 01:56:57 +02:00
# include <cstring>
2015-04-22 18:36:40 +02:00
using namespace std ;
using namespace std : : placeholders ;
2016-06-12 01:56:57 +02:00
using namespace ConversionUtilities ;
2015-04-22 18:36:40 +02:00
/*!
2016-06-12 01:56:57 +02:00
* \ namespace ApplicationUtilities
* \ brief Contains currently only ArgumentParser and related classes .
*/
2015-04-22 18:36:40 +02:00
namespace ApplicationUtilities {
2016-06-12 01:56:57 +02:00
/// \cond
2015-08-25 19:12:05 +02:00
const char * applicationName = nullptr ;
const char * applicationAuthor = nullptr ;
const char * applicationVersion = nullptr ;
const char * applicationUrl = nullptr ;
2016-05-25 01:24:17 +02:00
inline bool notEmpty ( const char * str )
{
return str & & * str ;
}
2016-06-12 01:56:57 +02:00
/// \endcond
2015-04-22 18:36:40 +02:00
/*!
* \ class ApplicationUtilities : : Argument
* \ brief The Argument class is a wrapper for command line argument information .
*
* Instaces of the Argument class are used as definition when parsing command line
* arguments . Arguments can be assigned to an ArgumentParser using
* ArgumentParser : : setMainArguments ( ) and to another Argument instance using
* Argument : : setSecondaryArguments ( ) .
*/
/*!
2016-02-27 01:19:16 +01:00
* \ brief Constructs an Argument with the given \ a name , \ a abbreviation and \ a description .
2015-04-22 18:36:40 +02:00
*
* The \ a name and the abbreviation mustn ' t contain any whitespaces .
* The \ a name mustn ' t be empty . The \ a abbreviation and the \ a description might be empty .
*/
2016-06-12 01:56:57 +02:00
Argument : : Argument ( const char * name , char abbreviation , const char * description , const char * example ) :
2016-05-25 01:24:17 +02:00
m_name ( name ) ,
m_abbreviation ( abbreviation ) ,
m_description ( description ) ,
m_example ( example ) ,
2016-06-12 01:56:57 +02:00
m_minOccurrences ( 0 ) ,
m_maxOccurrences ( 1 ) ,
2015-04-22 18:36:40 +02:00
m_combinable ( false ) ,
2015-05-08 23:20:47 +02:00
m_denotesOperation ( false ) ,
2015-04-22 18:36:40 +02:00
m_requiredValueCount ( 0 ) ,
2016-06-14 00:43:32 +02:00
m_implicit ( false ) ,
2015-04-22 18:36:40 +02:00
m_isMainArg ( false )
2016-05-25 01:24:17 +02:00
{ }
2015-04-22 18:36:40 +02:00
/*!
2016-02-27 01:19:16 +01:00
* \ brief Destroys the Argument .
2015-04-22 18:36:40 +02:00
*/
Argument : : ~ Argument ( )
{ }
/*!
2016-02-27 01:19:16 +01:00
* \ brief Appends the name , the abbreviation and the description of the Argument to the give ostream .
2015-04-22 18:36:40 +02:00
*/
void Argument : : printInfo ( ostream & os , unsigned char indentionLevel ) const
{
for ( unsigned char i = 0 ; i < indentionLevel ; + + i ) os < < " " ;
2016-05-25 01:24:17 +02:00
if ( notEmpty ( name ( ) ) ) {
2016-06-12 01:56:57 +02:00
os < < ' - ' < < ' - ' < < name ( ) ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
if ( notEmpty ( name ( ) ) & & abbreviation ( ) ) {
os < < ' , ' < < ' ' ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
if ( abbreviation ( ) ) {
os < < ' - ' < < abbreviation ( ) ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
if ( requiredValueCount ( ) ! = 0 ) {
unsigned int valueNamesPrint = 0 ;
2015-04-22 18:36:40 +02:00
for ( auto i = valueNames ( ) . cbegin ( ) , end = valueNames ( ) . cend ( ) ; i ! = end & & valueNamesPrint < requiredValueCount ( ) ; + + i ) {
2016-06-12 01:56:57 +02:00
os < < ' ' < < ' [ ' < < * i < < ' ] ' ;
2015-04-22 18:36:40 +02:00
+ + valueNamesPrint ;
}
2016-06-12 01:56:57 +02:00
if ( requiredValueCount ( ) = = static_cast < size_t > ( - 1 ) ) {
os < < " ... " ;
} else {
for ( ; valueNamesPrint < requiredValueCount ( ) ; + + valueNamesPrint ) {
os < < " [value " < < ( valueNamesPrint + 1 ) < < ' ] ' ;
}
2015-04-22 18:36:40 +02:00
}
}
+ + indentionLevel ;
2016-05-25 01:24:17 +02:00
if ( notEmpty ( description ( ) ) ) {
2015-04-22 18:36:40 +02:00
os < < endl ;
2016-06-12 01:56:57 +02:00
for ( unsigned char i = 0 ; i < indentionLevel ; + + i ) os < < ' ' < < ' ' ;
2015-04-22 18:36:40 +02:00
os < < description ( ) ;
}
if ( isRequired ( ) ) {
os < < endl ;
2016-06-12 01:56:57 +02:00
for ( unsigned char i = 0 ; i < indentionLevel ; + + i ) os < < ' ' < < ' ' ;
2015-04-22 18:36:40 +02:00
os < < " This argument is required. " ;
}
2016-05-25 01:24:17 +02:00
if ( notEmpty ( example ( ) ) ) {
2016-06-12 01:56:57 +02:00
for ( unsigned char i = 0 ; i < indentionLevel ; + + i ) os < < ' ' < < ' ' ;
2015-10-06 22:27:16 +02:00
os < < endl < < " Usage: " < < example ( ) ;
}
2015-04-22 18:36:40 +02:00
os < < endl ;
2016-06-11 19:41:40 +02:00
for ( const auto * arg : subArguments ( ) ) {
2015-04-22 18:36:40 +02:00
arg - > printInfo ( os , indentionLevel + 1 ) ;
}
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief This function return the first present and uncombinable argument of the given list of arguments .
*
2015-04-22 18:36:40 +02:00
* The Argument \ a except will be ignored .
*/
Argument * firstPresentUncombinableArg ( const ArgumentVector & args , const Argument * except )
{
for ( Argument * arg : args ) {
if ( arg ! = except & & arg - > isPresent ( ) & & ! arg - > isCombinable ( ) ) {
return arg ;
}
}
return nullptr ;
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief Sets the secondary arguments for this arguments .
*
* The given arguments will be considered as secondary arguments of this argument by the argument parser .
* This means that the parser will complain if these arguments are given , but not this argument .
* If secondary arguments are labeled as mandatory their parent is also mandatory .
2015-04-22 18:36:40 +02:00
*
* The Argument does not take ownership . Do not destroy the given arguments as long as they are
* used as secondary arguments .
*
* \ sa secondaryArguments ( )
2015-07-27 23:19:10 +02:00
* \ sa addSecondaryArgument ( )
2015-04-22 18:36:40 +02:00
* \ sa hasSecondaryArguments ( )
*/
2016-06-11 19:41:40 +02:00
void Argument : : setSubArguments ( const ArgumentInitializerList & secondaryArguments )
2015-04-22 18:36:40 +02:00
{
// remove this argument from the parents list of the previous secondary arguments
2016-06-11 19:41:40 +02:00
for ( Argument * arg : m_subArgs ) {
2015-04-22 18:36:40 +02:00
arg - > m_parents . erase ( remove ( arg - > m_parents . begin ( ) , arg - > m_parents . end ( ) , this ) , arg - > m_parents . end ( ) ) ;
}
// assign secondary arguments
2016-06-11 19:41:40 +02:00
m_subArgs . assign ( secondaryArguments ) ;
2015-04-22 18:36:40 +02:00
// add this argument to the parents list of the assigned secondary arguments
// and set the parser
2016-06-11 19:41:40 +02:00
for ( Argument * arg : m_subArgs ) {
2015-04-22 18:36:40 +02:00
if ( find ( arg - > m_parents . cbegin ( ) , arg - > m_parents . cend ( ) , this ) = = arg - > m_parents . cend ( ) ) {
arg - > m_parents . push_back ( this ) ;
}
}
}
2015-07-27 23:19:10 +02:00
/*!
2016-02-27 01:19:16 +01:00
* \ brief Adds \ a arg as a secondary argument for this argument .
2015-07-27 23:19:10 +02:00
*
* \ sa secondaryArguments ( )
* \ sa setSecondaryArguments ( )
* \ sa hasSecondaryArguments ( )
*/
2016-06-11 19:41:40 +02:00
void Argument : : addSubArgument ( Argument * arg )
2015-07-27 23:19:10 +02:00
{
2016-06-11 19:41:40 +02:00
if ( find ( m_subArgs . cbegin ( ) , m_subArgs . cend ( ) , arg ) = = m_subArgs . cend ( ) ) {
m_subArgs . push_back ( arg ) ;
2015-07-27 23:19:10 +02:00
if ( find ( arg - > m_parents . cbegin ( ) , arg - > m_parents . cend ( ) , this ) = = arg - > m_parents . cend ( ) ) {
arg - > m_parents . push_back ( this ) ;
}
}
}
2015-04-22 18:36:40 +02:00
/*!
2016-06-12 01:56:57 +02:00
* \ brief Returns whether at least one parent argument is present .
* \ remarks Returns always true for main arguments .
2015-04-22 18:36:40 +02:00
*/
bool Argument : : isParentPresent ( ) const
{
2016-06-12 01:56:57 +02:00
if ( isMainArgument ( ) ) {
return true ;
}
for ( const Argument * parent : m_parents ) {
2015-04-22 18:36:40 +02:00
if ( parent - > isPresent ( ) ) {
return true ;
}
}
return false ;
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief Checks if this arguments conflicts with other arguments .
*
* If the argument is in conflict with an other argument this argument will be returned .
* Otherwise nullptr will be returned .
2015-04-22 18:36:40 +02:00
*/
Argument * Argument : : conflictsWithArgument ( ) const
{
if ( ! isCombinable ( ) & & isPresent ( ) ) {
for ( Argument * parent : m_parents ) {
2016-06-11 19:41:40 +02:00
for ( Argument * sibling : parent - > subArguments ( ) ) {
2015-04-22 18:36:40 +02:00
if ( sibling ! = this & & sibling - > isPresent ( ) & & ! sibling - > isCombinable ( ) ) {
return sibling ;
}
}
}
}
return nullptr ;
}
2016-06-12 01:56:57 +02:00
/*!
* \ brief Resets occurrences and values .
*/
void Argument : : reset ( )
{
m_indices . clear ( ) ;
m_values . clear ( ) ;
}
2015-04-22 18:36:40 +02:00
/*!
* \ class ApplicationUtilities : : ArgumentParser
* \ brief The ArgumentParser class provides a means for handling command line arguments .
*
* To setup the parser create instances of ApplicationUtilities : : Argument to define a
* set of known arguments and assign these to the parser using setMainArguments ( ) .
*
* To invoke parsing call parseArgs ( ) . The parser will verify the previously
* assigned definitions ( and might throw std : : invalid_argument ) and then parse the
* given command line arguments according the definitions ( and might throw
* ApplicationUtilities : : Failure ) .
*/
/*!
2016-02-27 01:19:16 +01:00
* \ brief Constructs a new ArgumentParser .
2015-04-22 18:36:40 +02:00
*/
ArgumentParser : : ArgumentParser ( ) :
m_actualArgc ( 0 ) ,
2016-06-14 00:43:32 +02:00
m_executable ( nullptr ) ,
m_ignoreUnknownArgs ( false ) ,
m_defaultArg ( nullptr )
2015-04-22 18:36:40 +02:00
{ }
/*!
2016-02-27 01:19:16 +01:00
* \ brief Sets the main arguments for the parser . The parser will use these argument definitions
* to when parsing the command line arguments and when printing help information .
* \ remarks
2016-06-14 00:43:32 +02:00
* - The parser does not take ownership . Do not destroy the arguments as long as they are used as
* main arguments .
* - Sets the first specified argument as default argument if none is assigned yet and the
* first argument has no mandatory sub arguments .
2015-04-22 18:36:40 +02:00
*/
void ArgumentParser : : setMainArguments ( const ArgumentInitializerList & mainArguments )
{
2016-06-14 00:43:32 +02:00
if ( mainArguments . size ( ) ) {
for ( Argument * arg : mainArguments ) {
arg - > m_isMainArg = true ;
}
m_mainArgs . assign ( mainArguments ) ;
if ( ! m_defaultArg ) {
if ( ! ( * mainArguments . begin ( ) ) - > requiredValueCount ( ) ) {
bool subArgsRequired = false ;
for ( Argument * subArg : ( * mainArguments . begin ( ) ) - > subArguments ( ) ) {
if ( subArg - > isRequired ( ) ) {
subArgsRequired = true ;
break ;
}
}
if ( ! subArgsRequired ) {
m_defaultArg = * mainArguments . begin ( ) ;
}
}
}
} else {
m_mainArgs . clear ( ) ;
2015-04-22 18:36:40 +02:00
}
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief Adds the specified \ a argument to the main argument .
* \ remarks
* The parser does not take ownership . Do not destroy the argument as long as it is used as
* main argument .
*/
void ArgumentParser : : addMainArgument ( Argument * argument )
{
argument - > m_isMainArg = true ;
m_mainArgs . push_back ( argument ) ;
}
/*!
* \ brief Prints help information for all main arguments which have been set using setMainArguments ( ) .
2015-04-22 18:36:40 +02:00
*/
void ArgumentParser : : printHelp ( ostream & os ) const
{
2015-08-25 19:12:05 +02:00
if ( applicationName & & * applicationName ) {
os < < applicationName ;
if ( applicationVersion & & * applicationVersion ) {
os < < ' , ' < < ' ' ;
}
}
if ( applicationVersion & & * applicationVersion ) {
os < < " version " < < applicationVersion ;
}
if ( ( applicationName & & * applicationName ) | | ( applicationVersion & & * applicationVersion ) ) {
os < < ' \n ' < < ' \n ' ;
}
if ( ! m_mainArgs . empty ( ) ) {
os < < " Available arguments: \n " ;
2015-10-06 22:27:16 +02:00
for ( const auto * arg : m_mainArgs ) {
2015-08-25 19:12:05 +02:00
arg - > printInfo ( os ) ;
}
2015-04-22 18:36:40 +02:00
}
2015-08-25 19:12:05 +02:00
if ( applicationUrl & & * applicationUrl ) {
os < < " \n Project website: " < < applicationUrl < < endl ;
2015-04-22 18:36:40 +02:00
}
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief Returns the first argument definition which matches the predicate .
*
2015-04-22 18:36:40 +02:00
* The search includes all assigned main argument definitions and their sub arguments .
*/
Argument * ArgumentParser : : findArg ( const ArgumentPredicate & predicate ) const
{
return findArg ( m_mainArgs , predicate ) ;
}
/*!
2016-02-27 01:19:16 +01:00
* \ brief Returns the first argument definition which matches the predicate .
*
2015-04-22 18:36:40 +02:00
* The search includes all provided \ a arguments and their sub arguments .
*/
Argument * ArgumentParser : : findArg ( const ArgumentVector & arguments , const ArgumentPredicate & predicate )
{
for ( Argument * arg : arguments ) {
if ( predicate ( arg ) ) {
return arg ; // argument matches
2016-06-11 19:41:40 +02:00
} else if ( Argument * subarg = findArg ( arg - > subArguments ( ) , predicate ) ) {
2015-04-22 18:36:40 +02:00
return subarg ; // a secondary argument matches
}
}
return nullptr ; // no argument matches
}
2016-06-12 01:56:57 +02:00
/*!
* \ brief Parses the specified command line arguments .
* \ remarks
* - The results are stored in the Argument instances assigned as main arguments and sub arguments .
* - Calls the assigned callbacks if no constraints are violated .
* \ throws Throws Failure if the specified arguments violate the constraints defined
* by the Argument instances .
*/
void ArgumentParser : : parseArgs ( int argc , const char * argv [ ] )
{
IF_DEBUG_BUILD ( verifyArgs ( m_mainArgs ) ; )
m_actualArgc = 0 ;
2016-06-14 00:43:32 +02:00
if ( argc ) {
m_executable = * argv ;
if ( - - argc ) {
size_t index = 0 ;
+ + argv ;
readSpecifiedArgs ( m_mainArgs , index , argv , argv + argc ) ;
} else {
// no arguments specified -> set default argument as present
if ( m_defaultArg ) {
m_defaultArg - > m_indices . push_back ( 0 ) ;
m_defaultArg - > m_values . emplace_back ( ) ;
}
}
2016-06-12 01:56:57 +02:00
checkConstraints ( m_mainArgs ) ;
invokeCallbacks ( m_mainArgs ) ;
} else {
2016-06-14 00:43:32 +02:00
m_executable = nullptr ;
2016-06-12 01:56:57 +02:00
}
}
2016-05-25 01:24:17 +02:00
# ifdef DEBUG_BUILD
2015-04-22 18:36:40 +02:00
/*!
2016-06-12 01:56:57 +02:00
* \ brief Verifies the specified \ a argument definitions .
2015-04-22 18:36:40 +02:00
*
2016-06-12 01:56:57 +02:00
* Asserts that
* - The same argument has not been added twice to the same parent .
* - Only one argument within a parent is default or implicit .
* - Only main arguments denote operations .
* - Argument abbreviations are unique within one parent .
* - Argument names are unique within one parent .
2015-04-22 18:36:40 +02:00
*
2016-06-12 01:56:57 +02:00
* \ remarks
* - Verifies the sub arguments , too .
* - For debugging purposes only ; hence only available in debug builds .
2015-04-22 18:36:40 +02:00
*/
2016-06-12 01:56:57 +02:00
void ApplicationUtilities : : ArgumentParser : : verifyArgs ( const ArgumentVector & args )
2015-04-22 18:36:40 +02:00
{
2016-06-12 01:56:57 +02:00
vector < const Argument * > verifiedArgs ;
verifiedArgs . reserve ( args . size ( ) ) ;
vector < char > abbreviations ;
abbreviations . reserve ( args . size ( ) ) ;
2015-04-22 18:36:40 +02:00
vector < string > names ;
2016-06-12 01:56:57 +02:00
names . reserve ( args . size ( ) ) ;
2016-06-14 00:43:32 +02:00
bool hasImplicit = false ;
2016-06-12 01:56:57 +02:00
for ( const Argument * arg : args ) {
assert ( find ( verifiedArgs . cbegin ( ) , verifiedArgs . cend ( ) , arg ) = = verifiedArgs . cend ( ) ) ;
verifiedArgs . push_back ( arg ) ;
assert ( arg - > isMainArgument ( ) | | ! arg - > denotesOperation ( ) ) ;
2016-06-14 00:43:32 +02:00
assert ( ! arg - > isImplicit ( ) | | ! hasImplicit ) ;
hasImplicit | = arg - > isImplicit ( ) ;
2016-06-12 01:56:57 +02:00
assert ( ! arg - > abbreviation ( ) | | find ( abbreviations . cbegin ( ) , abbreviations . cend ( ) , arg - > abbreviation ( ) ) = = abbreviations . cend ( ) ) ;
abbreviations . push_back ( arg - > abbreviation ( ) ) ;
assert ( ! arg - > name ( ) | | find ( names . cbegin ( ) , names . cend ( ) , arg - > name ( ) ) = = names . cend ( ) ) ;
assert ( arg - > requiredValueCount ( ) = = 0 | | arg - > subArguments ( ) . size ( ) = = 0 ) ;
names . emplace_back ( arg - > name ( ) ) ;
verifyArgs ( arg - > subArguments ( ) ) ;
}
2015-04-22 18:36:40 +02:00
}
2016-05-25 01:24:17 +02:00
# endif
2015-04-22 18:36:40 +02:00
/*!
2016-06-12 01:56:57 +02:00
* \ brief Reads the specified commands line arguments .
* \ remarks Results are stored in Argument instances added as main arguments and sub arguments .
2015-04-22 18:36:40 +02:00
*/
2016-06-14 00:43:32 +02:00
void ArgumentParser : : readSpecifiedArgs ( ArgumentVector & args , std : : size_t & index , const char * * & argv , const char * * end , unsigned int level )
2015-04-22 18:36:40 +02:00
{
2016-06-12 01:56:57 +02:00
enum ArgumentDenotationType : unsigned char {
Value = 0 , // parameter value
Abbreviation = 1 , // argument abbreviation
FullName = 2 // full argument name
2015-07-27 23:19:10 +02:00
} ;
2016-06-12 01:56:57 +02:00
Argument * lastArg = nullptr ;
vector < const char * > * values = nullptr ;
while ( argv ! = end ) {
if ( values & & lastArg - > requiredValueCount ( ) ! = static_cast < size_t > ( - 1 ) & & values - > size ( ) < lastArg - > requiredValueCount ( ) ) {
// there are still values to read
values - > emplace_back ( * argv ) ;
+ + index , + + argv ;
} else {
// determine denotation type
const char * argDenotation = * argv ;
bool abbreviationFound = false ;
unsigned char argDenotationType = Value ;
* argDenotation = = ' - ' & & ( + + argDenotation , + + argDenotationType )
& & * argDenotation = = ' - ' & & ( + + argDenotation , + + argDenotationType ) ;
// try to find matching Argument instance
Argument * matchingArg = nullptr ;
if ( argDenotationType ! = Value ) {
const char * const equationPos = strchr ( argDenotation , ' = ' ) ;
for ( const auto argDenLen = equationPos ? static_cast < size_t > ( equationPos - argDenotation ) : strlen ( argDenotation ) ; ; matchingArg = nullptr ) {
// search for arguments by abbreviation or name depending on the denotation type
if ( argDenotationType = = Abbreviation ) {
for ( Argument * arg : args ) {
if ( arg - > abbreviation ( ) & & arg - > abbreviation ( ) = = * argDenotation ) {
matchingArg = arg ;
abbreviationFound = true ;
break ;
2015-04-22 18:36:40 +02:00
}
}
} else {
2016-06-12 01:56:57 +02:00
for ( Argument * arg : args ) {
if ( arg - > name ( ) & & ! strncmp ( arg - > name ( ) , argDenotation , argDenLen ) ) {
matchingArg = arg ;
break ;
}
}
}
if ( matchingArg ) {
// an argument matched the specified denotation
matchingArg - > m_indices . push_back ( index ) ;
// prepare reading parameter values
matchingArg - > m_values . emplace_back ( ) ;
values = & matchingArg - > m_values . back ( ) ;
if ( equationPos ) {
values - > push_back ( equationPos + 1 ) ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
// read sub arguments if no abbreviated argument follows
+ + index , + + m_actualArgc , lastArg = matchingArg ;
if ( argDenotationType ! = Abbreviation | | ( ! * + + argDenotation & & argDenotation ! = equationPos ) ) {
2016-06-14 00:43:32 +02:00
readSpecifiedArgs ( matchingArg - > m_subArgs , index , + + argv , end , level + 1 ) ;
2016-06-12 01:56:57 +02:00
break ;
} // else: another abbreviated argument follows
} else {
break ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
}
}
if ( ! matchingArg ) {
if ( lastArg & & values - > size ( ) < lastArg - > requiredValueCount ( ) ) {
// treat unknown argument as parameter of last argument
values - > emplace_back ( abbreviationFound ? argDenotation : * argv ) ;
+ + index , + + argv ;
continue ;
2015-04-22 18:36:40 +02:00
} else {
2016-06-12 01:56:57 +02:00
// first value might denote "operation"
2016-06-14 00:43:32 +02:00
if ( ! level ) {
2016-06-12 01:56:57 +02:00
for ( Argument * arg : args ) {
if ( arg - > denotesOperation ( ) & & arg - > name ( ) & & ! strcmp ( arg - > name ( ) , * argv ) ) {
( matchingArg = arg ) - > m_indices . push_back ( index ) ;
+ + index , + + argv ;
break ;
2015-05-08 23:20:47 +02:00
}
2015-04-22 18:36:40 +02:00
}
}
2016-06-12 01:56:57 +02:00
if ( ! matchingArg ) {
// use the first default argument
for ( Argument * arg : args ) {
2016-06-14 23:11:13 +02:00
if ( arg - > isImplicit ( ) & & ! arg - > isPresent ( ) ) {
2016-06-12 01:56:57 +02:00
( matchingArg = arg ) - > m_indices . push_back ( index ) ;
break ;
}
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
}
if ( matchingArg ) {
// an argument matched the specified denotation
if ( lastArg = = matchingArg ) {
break ;
}
// prepare reading parameter values
matchingArg - > m_values . emplace_back ( ) ;
values = & matchingArg - > m_values . back ( ) ;
// read sub arguments if no abbreviated argument follows
+ + m_actualArgc , lastArg = matchingArg ;
2016-06-14 00:43:32 +02:00
readSpecifiedArgs ( matchingArg - > m_subArgs , index , argv , end , level + 1 ) ;
2016-06-12 01:56:57 +02:00
continue ;
}
}
2016-06-14 00:43:32 +02:00
if ( ! level ) {
2016-06-12 01:56:57 +02:00
if ( m_ignoreUnknownArgs ) {
cerr < < " The specified argument \" " < < * argv < < " \" is unknown and will be ignored. " < < endl ;
+ + index , + + argv ;
2015-04-22 18:36:40 +02:00
} else {
2016-06-12 01:56:57 +02:00
throw Failure ( " The specified argument \" " + string ( * argv ) + " \" is unknown and will be ignored. " ) ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
} else {
return ; // unknown argument name or abbreviation found -> continue with parent level
2015-04-22 18:36:40 +02:00
}
}
}
}
2016-06-12 01:56:57 +02:00
}
/*!
* \ brief Checks the constrains of the specified \ a args .
* \ remarks Checks the contraints of sub arguments , too .
*/
void ArgumentParser : : checkConstraints ( const ArgumentVector & args )
{
for ( const Argument * arg : args ) {
const auto occurrences = arg - > occurrences ( ) ;
if ( arg - > isParentPresent ( ) & & occurrences > arg - > maxOccurrences ( ) ) {
throw Failure ( " The argument \" " + string ( arg - > name ( ) ) + " \" mustn't be specified more than " + numberToString ( arg - > maxOccurrences ( ) ) + ( arg - > maxOccurrences ( ) = = 1 ? " time. " : " times. " ) ) ;
2015-07-27 23:19:10 +02:00
}
2016-06-12 01:56:57 +02:00
if ( arg - > isParentPresent ( ) & & occurrences < arg - > minOccurrences ( ) ) {
throw Failure ( " The argument \" " + string ( arg - > name ( ) ) + " \" must be specified at least " + numberToString ( arg - > minOccurrences ( ) ) + ( arg - > minOccurrences ( ) = = 1 ? " time. " : " times. " ) ) ;
}
Argument * conflictingArgument = nullptr ;
if ( arg - > isMainArgument ( ) ) {
if ( ! arg - > isCombinable ( ) & & arg - > isPresent ( ) ) {
conflictingArgument = firstPresentUncombinableArg ( m_mainArgs , arg ) ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
} else {
conflictingArgument = arg - > conflictsWithArgument ( ) ;
}
if ( conflictingArgument ) {
throw Failure ( " The argument \" " + string ( conflictingArgument - > name ( ) ) + " \" can not be combined with \" " + arg - > name ( ) + " \" . " ) ;
}
for ( size_t i = 0 ; i ! = occurrences ; + + i ) {
2016-06-14 00:43:32 +02:00
if ( ! arg - > allRequiredValuesPresent ( i ) ) {
2015-04-22 18:36:40 +02:00
stringstream ss ( stringstream : : in | stringstream : : out ) ;
2016-06-12 01:56:57 +02:00
ss < < " Not all parameter for argument \" " < < arg - > name ( ) < < " \" " ;
if ( i ) {
ss < < " ( " < < ( i + 1 ) < < " occurrence) " ;
}
ss < < " provided. You have to provide the following parameter: " ;
size_t valueNamesPrint = 0 ;
2015-04-22 18:36:40 +02:00
for ( const auto & name : arg - > m_valueNames ) {
2016-06-14 00:43:32 +02:00
ss < < ' ' < < name , + + valueNamesPrint ;
2015-04-22 18:36:40 +02:00
}
2016-06-12 01:56:57 +02:00
if ( arg - > m_requiredValueCount ! = static_cast < size_t > ( - 1 ) ) {
while ( valueNamesPrint < arg - > m_requiredValueCount ) {
ss < < " \n value " < < ( + + valueNamesPrint ) ;
}
2015-04-22 18:36:40 +02:00
}
throw Failure ( ss . str ( ) ) ;
}
}
2016-06-12 01:56:57 +02:00
// check contraints of sub arguments recursively
checkConstraints ( arg - > m_subArgs ) ;
}
}
/*!
* \ brief Invokes the callbacks for the specified \ a args .
* \ remarks
* - Checks the callbacks for sub arguments , too .
* - Invokes the assigned callback methods for each occurance of
* the argument .
*/
void ArgumentParser : : invokeCallbacks ( const ArgumentVector & args )
{
for ( const Argument * arg : args ) {
// invoke the callback for each occurance of the argument
2015-04-22 18:36:40 +02:00
if ( arg - > m_callbackFunction ) {
2016-06-12 01:56:57 +02:00
for ( const auto & valuesOfOccurance : arg - > m_values ) {
2016-06-14 00:43:32 +02:00
arg - > m_callbackFunction ( valuesOfOccurance ) ;
2015-04-22 18:36:40 +02:00
}
}
2016-06-12 01:56:57 +02:00
// invoke the callbacks for sub arguments recursively
invokeCallbacks ( arg - > m_subArgs ) ;
}
2015-04-22 18:36:40 +02:00
}
/*!
2016-06-10 22:59:22 +02:00
* \ class HelpArgument
2015-04-22 18:36:40 +02:00
* \ brief The HelpArgument class prints help information for an argument parser
* when present ( - - help , - h ) .
*/
/*!
* \ brief Constructs a new help argument for the specified parser .
*/
HelpArgument : : HelpArgument ( ArgumentParser & parser ) :
2016-06-12 01:56:57 +02:00
Argument ( " help " , ' h ' , " shows this information " )
2015-04-22 18:36:40 +02:00
{
2016-06-12 01:56:57 +02:00
setCallback ( [ & parser ] ( const std : : vector < const char * > & ) {
2015-09-01 20:05:38 +02:00
CMD_UTILS_START_CONSOLE ;
parser . printHelp ( cout ) ;
} ) ;
2015-04-22 18:36:40 +02:00
}
}