31#ifndef ARGS__CMD_LINE_HPP__INCLUDED
32#define ARGS__CMD_LINE_HPP__INCLUDED
58#ifdef ARGS_WSTRING_BUILD
59 makeContext(
int argc,
const Char *
const * argv )
61 makeContext(
int argc,
const char *
const * argv )
67 for(
int i = 1; i < argc; ++i )
68 context.push_back( argv[ i ] );
80formatCorrectNamesString(
const StringList & names )
88 for(
const auto & name : details::
asConst( names ) )
91 res.append(
SL(
" or " ) );
111template<
typename PARENT,
typename SELF,
typename ARGPTR >
114using ArgPtrToAPI = std::unique_ptr< ArgIface, details::Deleter< ArgIface > >;
122 :
public CmdLineAPI< CmdLine, CmdLine, ArgPtrToAPI >
146 , m_command( nullptr )
147 , m_currCommand( nullptr )
152#ifdef ARGS_WSTRING_BUILD
158 CmdLine(
int argc,
const char *
const * argv,
181 if( std::find( m_args.begin(), m_args.end(), arg ) ==
184 arg->setCmdLine(
this );
186 m_args.push_back( std::move( arg ) );
190 arg->name() +
SL(
"\" already in the command line parser." ) );
196#ifdef ARGS_WSTRING_BUILD
198 void parse(
int argc,
const Char *
const * argv )
201 void parse(
int argc,
const char *
const * argv )
204 m_context = std::move( details::makeContext( argc, argv ) );
218 return m_positionalDescription;
224 m_positionalDescription = d;
231 auto it = std::find_if( m_args.begin(),
232 m_args.end(), [ &name ] (
const auto & arg ) ->
bool
233 { return ( arg->findArgument( name ) != nullptr ); } );
235 if( it != m_args.end() )
240 return (*it)->findArgument( name );
242 else if( !m_prevCommand.empty() )
244 for(
const auto & c : m_prevCommand )
246 ArgIface * tmp = c->findChild( name );
260 auto it = std::find_if( m_args.cbegin(),
261 m_args.cend(), [ &name ] (
const auto & arg ) ->
bool
262 { return ( arg->findArgument( name ) != nullptr ); } );
264 if( it != m_args.end() )
269 return (*it)->findArgument( name );
271 else if( !m_prevCommand.empty() )
273 for(
const auto & c : m_prevCommand )
275 ArgIface * tmp = c->findChild( name );
298 [ & ] (
const auto & arg )
302 if( arg.get() == m_command )
304 if( arg->isMisspelledName( name, possibleNames ) )
307 else if(
static_cast< Command*
> ( arg.get() )->
308 isMisspelledCommand( name, possibleNames ) )
311 else if( arg->isMisspelledName( name, possibleNames ) )
321 bool throwExceptionOnPrint =
true,
327 String::size_type length = 79,
331 auto help = std::unique_ptr< Help, details::Deleter< ArgIface > >
332 (
new Help( throwExceptionOnPrint ),
335 if( !appExe.empty() )
336 help->setExecutable( appExe );
338 if( !appDesc.empty() )
339 help->setAppDescription( appDesc );
341 if( !posDesc.empty() )
342 setPositionalDescription( posDesc );
344 help->setLineLength( length );
346 ArgPtr arg = std::move( help );
348 addArg( std::move( arg ) );
353 template<
typename T >
357 String::size_type length = 79 ) =
delete;
363 const String & name )
const
365 const auto * arg = findArgument( name );
369 switch( arg->type() )
372 return (
static_cast< const Command*
> ( arg )->value() );
375 return (
static_cast< const Arg*
> ( arg )->value() );
378 return (
static_cast< const MultiArg*
> ( arg )->value() );
392 const String & name )
const
394 const auto * arg = findArgument( name );
398 switch( arg->type() )
401 return (
static_cast< const Command*
> ( arg )->values() );
405 { (
static_cast< const Arg*
> ( arg )->value() ) } );
424 const String & name )
const
426 const auto * arg = findArgument( name );
429 return arg->isDefined();
437 std::for_each( arguments().begin(), arguments().end(),
438 [] (
const auto & a ) { a->clear(); } );
441 m_currCommand =
nullptr;
442 m_prevCommand.clear();
447 void checkCorrectnessBeforeParsing()
const;
449 void checkCorrectnessAfterParsing()
const;
452 void printInfoAboutUnknownArgument(
const String & word )
456 if( isMisspelledName( word, correctNames ) )
458 const String names = details::formatCorrectNamesString(
462 word +
SL(
"\".\n\nProbably you mean \"" ) + names +
466 throw BaseException(
String(
SL(
"Unknown argument \"" ) ) +
467 word +
SL(
"\"." ) );
471 void savePositionalArguments(
const String & word,
bool splitted,
bool valuePrepended )
477 tmp.append( 1,
'=' );
480 tmp.append( *m_context.next() );
483 if( tmp !=
String( 2,
'-' ) )
484 m_positional.push_back( tmp );
486 while( !m_context.atEnd() )
488 auto it = m_context.next();
490 m_positional.push_back( *it );
506 std::vector< Command * > m_prevCommand;
512 String m_positionalDescription;
521#ifdef ARGS_WSTRING_BUILD
522 CmdLine::CmdLine(
int argc,
const Char *
const * argv, CmdLineOpts opt )
524 CmdLine::CmdLine(
int argc,
const char *
const * argv,
CmdLineOpts opt )
527 , m_context( details::makeContext( argc, argv ) )
528 , m_command(
nullptr )
529 , m_currCommand(
nullptr )
539 if( std::find( m_args.begin(), m_args.end(),
545 m_args.push_back(
ArgPtr( arg,
550 arg->
name() +
SL(
"\" already in the command line parser." ) );
554 "command line as argument." ) ) );
568 checkCorrectnessBeforeParsing();
570 while( !m_context.atEnd() )
572 String word = *m_context.next();
574 const String::size_type eqIt = word.find(
'=' );
576 bool splitted =
false;
577 bool valuePrepended =
false;
579 if( eqIt != String::npos )
583 const String value = word.substr( eqIt + 1 );
587 valuePrepended =
true;
588 m_context.prepend( value );
591 word = word.substr( 0, eqIt );
594 if( details::isArgument( word ) )
596 auto * arg = findArgument( word );
599 arg->process( m_context );
600 else if( m_opt & HandlePositionalArguments )
601 savePositionalArguments( word, splitted, valuePrepended );
603 printInfoAboutUnknownArgument( word );
605 else if( details::isFlag( word ) )
607 std::vector< ArgIface* > tmpArgs;
610 for( String::size_type i = 1, length = word.length(); i < length; ++i )
614#ifdef ARGS_QSTRING_BUILD
620 auto * arg = findArgument( flag );
626 if( !( m_opt & HandlePositionalArguments ) )
628 flag +
SL(
"\"." ) );
633 tmpArgs.push_back( arg );
635 if( i < length - 1 && arg->isWithValue() )
639 if( !( m_opt & HandlePositionalArguments ) )
641 "flags combo can be with value. Flags combo is \"" ) ) +
642 word +
SL(
"\"." ) );
647 arg->process( m_context );
650 if( failed && ( m_opt & HandlePositionalArguments ) )
652 for(
auto * a : tmpArgs )
655 savePositionalArguments( word, splitted, valuePrepended );
661 auto * tmp = findArgument( word );
663 auto check = [
this, &tmp, &word] ()
665 const auto & args = m_args;
667 const auto it = std::find_if( args.cbegin(),
668 args.cend(), [&tmp] (
const auto & arg ) ->
bool
669 { return ( arg.get() == tmp ); } );
671 if( m_command && it != args.cend() && !m_command->findChild( word ) )
673 "Only one command from one level can be specified. "
674 "But you defined \"" ) ) +
675 word +
SL(
"\" and \"" ) + m_command->name() +
SL(
"\"." ) );
680 if( tmp->type() == ArgType::Command )
682 bool stopProcessing =
false;
685 if( !m_prevCommand.empty() )
687 for(
const auto & prev : m_prevCommand )
689 const auto & args = prev->children();
691 const auto it = std::find_if( args.cbegin(),
692 args.cend(), [&tmp] (
const auto & arg ) ->
bool
693 { return ( arg.get() == tmp ); } );
695 if( it != args.cend() && !m_currCommand->findChild( word ) )
697 "Only one command from one level can be specified. "
698 "But you defined \"" ) ) +
699 word +
SL(
"\" and \"" ) + prev->name() +
SL(
"\"." ) );
709 if( m_opt & HandlePositionalArguments )
711 savePositionalArguments( word, splitted, valuePrepended );
713 stopProcessing =
true;
724 m_command =
static_cast< Command*
> ( tmp );
726 m_currCommand = m_command;
728 m_prevCommand.push_back( m_command );
730 m_command->
process( m_context );
734 auto * cmd =
static_cast< Command*
> ( tmp );
740 m_prevCommand.push_back( m_currCommand );
742 m_currCommand->process( m_context );
745 else if( m_opt & HandlePositionalArguments )
746 savePositionalArguments( word, splitted, valuePrepended );
748 printInfoAboutUnknownArgument( word );
750 else if( m_opt & HandlePositionalArguments )
751 savePositionalArguments( word, splitted, valuePrepended );
753 printInfoAboutUnknownArgument( word );
757 checkCorrectnessAfterParsing();
761CmdLine::arguments()
const
767CmdLine::checkCorrectnessBeforeParsing()
const
772 std::vector< ArgIface* > cmds;
774 std::for_each( m_args.cbegin(), m_args.cend(),
775 [ &cmds, &flags, &names ] (
const auto & arg )
777 if( arg->type() == ArgType::Command )
778 cmds.push_back( arg.get() );
780 arg->checkCorrectnessBeforeParsing( flags, names );
784 std::for_each( cmds.cbegin(), cmds.cend(),
785 [ &flags, &names ] (
ArgIface * arg )
786 { arg->checkCorrectnessBeforeParsing( flags, names ); }
791CmdLine::checkCorrectnessAfterParsing()
const
793 std::for_each( m_args.begin(), m_args.end(),
794 [] (
const auto & arg )
795 { arg->checkCorrectnessAfterParsing(); }
798 if( m_opt & CommandIsRequired && !m_command )
799 throw BaseException(
SL(
"Not specified command." ) );
810 :
Arg(
SL(
'h' ),
SL(
"help" ), true, false )
812 , m_throwExceptionOnPrint( throwExceptionOnPrint )
Argument with one value that can be present only once in the command line.
void setLongDescription(const String &desc)
Set long description.
void setDescription(const String &desc)
Set description.
virtual String name() const =0
virtual void setCmdLine(CmdLine *cmdLine)
Set command line parser.
Base exception of the library.
CmdLine is class that holds all rguments and parse command line arguments in the correspondence with ...
void parse(int argc, const char *const *argv)
Parse arguments.
const StringList & positional() const
CmdLine & addHelp(bool throwExceptionOnPrint=true, const String &appExe=String(), const String &appDesc=String(), String::size_type length=79, const String &posDesc=String())
Add help.
bool isMisspelledName(const String &name, StringList &possibleNames) const
void addArg(ArgIface *arg)
Add argument.
bool isDefined(const String &name) const
String value(const String &name) const
CmdLine(CmdLineOpts opt=Empty)
Construct empty CmdLine.
void parse()
Parse arguments.
void clear()
Clear state of the arguments.
const ArgIface * findArgument(const String &name) const
CmdLineOpt
Command line options.
@ Empty
No special options.
@ HandlePositionalArguments
Handle positional arguments.
@ CommandIsRequired
Command should be defined.
void addHelp(T throwExceptionOnPrint, const String &appExe=String(), const String &appDesc=String(), String::size_type length=79)=delete
StringList values(const String &name) const
int CmdLineOpts
Storage of command line options.
void setPositionalDescription(const String &d)
Set positional string description for the help.
ArgPtrToAPI ArgPtr
Smart pointer to the argument.
const String & positionalDescription() const
ArgIface * findArgument(const String &name)
void addArg(ArgPtr arg)
Add argument.
const Arguments & arguments() const
std::vector< ArgPtr > Arguments
List of child arguments.
CmdLineOpts parserOptions() const
Command in the command line interface.
void process(Context &ctx) override
Process argument's staff, for example take values from context.
void setCurrentSubCommand(Command *sub)
Set current subcommand.
Help(bool throwExceptionOnPrint=true)
HelpPrinter is a class that prints help.
MultiArg is a class that presents argument in the command line taht can be presented more than once o...
virtual const StringList & values() const
API(PARENT &parent, SELF &self)
constexpr std::add_const< T >::type & asConst(T &t) noexcept
Adds const to non-const objects.
std::string String
String type.
std::vector< String > StringList
List of strings.
std::unique_ptr< ArgIface, details::Deleter< ArgIface > > ArgPtrToAPI
@ MultiArg
Multi argument.
StringList ContextInternal
What Context actually is.
String::value_type Char
Char type.
#define DISABLE_COPY(Class)
Macro for disabling copy.