7#ifndef ARGS__CMD_LINE_HPP__INCLUDED
8#define ARGS__CMD_LINE_HPP__INCLUDED
35#ifdef ARGS_WSTRING_BUILD
37 const Char *
const *argv)
40 const char *
const *argv)
46 for (
int i = 1; i < argc; ++i) {
47 context.push_back(argv[i]);
67 res.append(
SL(
" or "));
87template<
typename PARENT,
typename SELF,
typename ARGPTR>
90using ArgPtrToAPI = std::unique_ptr<ArgIface, details::Deleter<ArgIface>>;
126 , m_currCommand(nullptr)
131#ifdef ARGS_WSTRING_BUILD
134 const Char *
const *argv,
139 const char *
const *argv,
162 if (std::find(m_args.begin(), m_args.end(), arg) == m_args.end()) {
163 arg->setCmdLine(
this);
165 m_args.push_back(std::move(arg));
175#ifdef ARGS_WSTRING_BUILD
178 const Char *
const *argv)
182 const char *
const *argv)
185 m_context = std::move(details::makeContext(argc, argv));
199 return m_positionalDescription;
205 m_positionalDescription = d;
213 auto it = std::find_if(m_args.begin(), m_args.end(), [&name](
const auto &arg) ->
bool {
214 return (arg->findArgument(name) != nullptr);
217 if (it != m_args.end()) {
221 return (*it)->findArgument(name);
223 }
else if (!m_prevCommand.empty()) {
224 for (
const auto &c : m_prevCommand) {
240 auto it = std::find_if(m_args.cbegin(), m_args.cend(), [&name](
const auto &arg) ->
bool {
241 return (arg->findArgument(name) != nullptr);
244 if (it != m_args.end()) {
248 return (*it)->findArgument(name);
250 }
else if (!m_prevCommand.empty()) {
251 for (
const auto &c : m_prevCommand) {
277 if (arg.get() == m_command) {
278 if (arg->isMisspelledName(name, possibleNames))
283 }
else if (arg->isMisspelledName(name, possibleNames)) {
294 bool throwExceptionOnPrint =
true,
300 String::size_type length = 79,
304 auto help = std::unique_ptr<Help, details::Deleter<ArgIface>>(
new Help(throwExceptionOnPrint),
307 if (!appExe.empty()) {
308 help->setExecutable(appExe);
311 if (!appDesc.empty()) {
312 help->setAppDescription(appDesc);
315 if (!posDesc.empty()) {
319 help->setLineLength(length);
321 ArgPtr arg = std::move(help);
332 String::size_type length = 79) =
delete;
343 switch (arg->type()) {
348 return (
static_cast<const Arg *
>(arg)->
value());
370 switch (arg->type()) {
399 return arg->isDefined();
413 m_currCommand =
nullptr;
414 m_prevCommand.clear();
419 void checkCorrectnessBeforeParsing()
const;
421 void checkCorrectnessAfterParsing()
const;
424 void printInfoAboutUnknownArgument(
const String &word)
429 const String names = details::formatCorrectNamesString(correctNames);
432 String(
SL(
"Unknown argument \"")) + word +
SL(
"\".\n\nProbably you mean \"") + names +
SL(
"\"."));
434 throw BaseException(
String(
SL(
"Unknown argument \"")) + word +
SL(
"\"."));
439 void savePositionalArguments(
const String &word,
448 if (valuePrepended) {
449 tmp.append(*m_context.next());
453 if (tmp !=
String(2,
'-')) {
454 m_positional.push_back(tmp);
457 while (!m_context.atEnd()) {
458 auto it = m_context.next();
460 m_positional.push_back(*it);
476 std::vector<Command *> m_prevCommand;
482 String m_positionalDescription;
490#ifdef ARGS_WSTRING_BUILD
492 const Char *
const *argv,
496 const char *
const *argv,
504 , m_context(details::makeContext(argc,
507 , m_currCommand(
nullptr)
524 String(
SL(
"Attempt to add nullptr to the "
525 "command line as argument.")));
539 checkCorrectnessBeforeParsing();
541 while (!m_context.atEnd()) {
542 String word = *m_context.next();
544 const String::size_type eqIt = word.find(
'=');
546 bool splitted =
false;
547 bool valuePrepended =
false;
549 if (eqIt != String::npos) {
554 if (!
value.empty()) {
555 valuePrepended =
true;
556 m_context.prepend(
value);
559 word = word.substr(0, eqIt);
562 if (details::isArgument(word)) {
566 arg->process(m_context);
568 savePositionalArguments(word, splitted, valuePrepended);
570 printInfoAboutUnknownArgument(word);
572 }
else if (details::isFlag(word)) {
573 std::vector<ArgIface *> tmpArgs;
576 for (String::size_type i = 1, length = word.length(); i < length; ++i) {
579#ifdef ARGS_QSTRING_BUILD
596 tmpArgs.push_back(arg);
599 if (i < length - 1 && arg->isWithValue()) {
604 "flags combo can be with value. Flags combo is \""))
611 arg->process(m_context);
616 for (
auto *a : tmpArgs) {
620 savePositionalArguments(word, splitted, valuePrepended);
627 auto check = [
this, &tmp, &word]() {
628 const auto &args = m_args;
630 const auto it = std::find_if(args.cbegin(), args.cend(), [&tmp](
const auto &arg) ->
bool {
631 return (arg.get() == tmp);
634 if (m_command && it != args.cend() && !m_command->findChild(word)) {
636 "But you defined \""))
646 bool stopProcessing =
false;
649 if (!m_prevCommand.empty()) {
650 for (
const auto &prev : m_prevCommand) {
651 const auto &args = prev->children();
654 std::find_if(args.cbegin(), args.cend(), [&tmp](
const auto &arg) ->
bool {
655 return (arg.get() == tmp);
658 if (it != args.cend() && !m_currCommand->findChild(word)) {
660 "But you defined \""))
674 savePositionalArguments(word, splitted, valuePrepended);
676 stopProcessing =
true;
682 if (stopProcessing) {
687 m_command =
static_cast<Command *
>(tmp);
689 m_currCommand = m_command;
691 m_prevCommand.push_back(m_command);
695 auto *cmd =
static_cast<Command *
>(tmp);
701 m_prevCommand.push_back(m_currCommand);
703 m_currCommand->process(m_context);
706 savePositionalArguments(word, splitted, valuePrepended);
708 printInfoAboutUnknownArgument(word);
711 savePositionalArguments(word, splitted, valuePrepended);
713 printInfoAboutUnknownArgument(word);
718 checkCorrectnessAfterParsing();
726inline void CmdLine::checkCorrectnessBeforeParsing()
const
731 std::vector<ArgIface *> cmds;
733 std::for_each(m_args.cbegin(), m_args.cend(), [&cmds, &flags, &names](
const auto &arg) {
734 if (arg->type() == ArgType::Command) {
735 cmds.push_back(arg.get());
737 arg->checkCorrectnessBeforeParsing(flags, names);
741 std::for_each(cmds.cbegin(), cmds.cend(), [&flags, &names](ArgIface *arg) {
742 arg->checkCorrectnessBeforeParsing(flags, names);
746inline void CmdLine::checkCorrectnessAfterParsing()
const
748 std::for_each(m_args.begin(), m_args.end(), [](
const auto &arg) {
749 arg->checkCorrectnessAfterParsing();
752 if (m_opt & CommandIsRequired && !m_command) {
753 throw BaseException(
SL(
"Not specified command."));
770 , m_throwExceptionOnPrint(throwExceptionOnPrint)
Argument with one value that can be present only once in the command line.
Arg & setLongDescription(const String &desc)
Set long description.
virtual const String & value() const
Arg(Char flag, T &&name, bool isWithValue=false, bool isRequired=false)
Construct argument with flag and name.
Arg & 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.
CmdLine & addArg(ArgIface *arg)
Add argument.
bool isMisspelledName(const String &name, StringList &possibleNames) const
CmdLine & setPositionalDescription(const String &d)
Set positional string description for the help.
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.
std::vector< ArgPtr > Arguments
List of child arguments.
ArgPtrToAPI ArgPtr
Smart pointer to the argument.
const String & positionalDescription() const
ArgIface * findArgument(const String &name)
const Arguments & arguments() const
CmdLine & addArg(ArgPtr arg)
Add argument.
CmdLineOpts parserOptions() const
Command in the command line interface.
bool isMisspelledCommand(const String &nm, StringList &possibleNames) const
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...
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.
@ MultiArg
Multi argument.
StringList ContextInternal
What Context actually is.
String::value_type Char
Char type.
details::API< PARENT, SELF, ARGPTR, true > CmdLineAPI
std::unique_ptr< ArgIface, details::Deleter< ArgIface > > ArgPtrToAPI
std::vector< String > StringList
List of strings.
#define DISABLE_COPY(Class)
Macro for disabling copy.