Improve CLI utils
- Add ArgumentParser::readArgs() - Add Indentation - Fix eraseLine()
This commit is contained in:
parent
4d0807de9b
commit
4c40004f0b
|
@ -12,9 +12,6 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#ifdef LOGGING_ENABLED
|
|
||||||
# include <fstream>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
|
@ -110,9 +107,9 @@ const char *Argument::firstValue() const
|
||||||
/*!
|
/*!
|
||||||
* \brief Writes the name, the abbreviation and other information about the Argument to the give ostream.
|
* \brief Writes the name, the abbreviation and other information about the Argument to the give ostream.
|
||||||
*/
|
*/
|
||||||
void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
void Argument::printInfo(ostream &os, unsigned char indentation) const
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
os << Indentation(indentation);
|
||||||
EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold);
|
EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold);
|
||||||
if(notEmpty(name())) {
|
if(notEmpty(name())) {
|
||||||
os << '-' << '-' << name();
|
os << '-' << '-' << name();
|
||||||
|
@ -138,24 +135,25 @@ void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++indentionLevel;
|
indentation += 2;
|
||||||
if(notEmpty(description())) {
|
if(notEmpty(description())) {
|
||||||
os << endl;
|
os << '\n' << Indentation(indentation) << description();
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
|
||||||
os << description();
|
|
||||||
}
|
}
|
||||||
if(isRequired()) {
|
if(isRequired()) {
|
||||||
os << endl;
|
os << '\n' << Indentation(indentation) << "particularities: mandatory";
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
if(!isMainArgument()) {
|
||||||
os << "This argument is required.";
|
os << " if parent argument is present";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(environmentVariable()) {
|
||||||
|
os << '\n' << Indentation(indentation) << "default environment variable: " << environmentVariable();
|
||||||
}
|
}
|
||||||
if(notEmpty(example())) {
|
if(notEmpty(example())) {
|
||||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
os << '\n' << Indentation(indentation) << "\nusage: " << example();
|
||||||
os << endl << "Usage: " << example();
|
|
||||||
}
|
}
|
||||||
os << endl;
|
os << '\n';
|
||||||
for(const auto *arg : subArguments()) {
|
for(const auto *arg : subArguments()) {
|
||||||
arg->printInfo(os, indentionLevel + 1);
|
arg->printInfo(os, indentation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,21 +363,32 @@ void ArgumentParser::printHelp(ostream &os) const
|
||||||
* \remarks
|
* \remarks
|
||||||
* - The results are stored in the Argument instances assigned as main arguments and sub arguments.
|
* - The results are stored in the Argument instances assigned as main arguments and sub arguments.
|
||||||
* - Calls the assigned callbacks if no constraints are violated.
|
* - Calls the assigned callbacks if no constraints are violated.
|
||||||
* \throws Throws Failure if the specified arguments violate the constraints defined
|
* \throws Throws Failure if the specified arguments are invalid or violate the constraints defined
|
||||||
* by the Argument instances.
|
* by the Argument instances.
|
||||||
|
* \sa readArgs()
|
||||||
*/
|
*/
|
||||||
void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
||||||
{
|
{
|
||||||
#ifdef LOGGING_ENABLED
|
readArgs(argc, argv);
|
||||||
{
|
if(argc) {
|
||||||
fstream logFile("/tmp/args.log", ios_base::out);
|
checkConstraints(m_mainArgs);
|
||||||
for(const char *const *i = argv, *const *end = argv + argc; i != end; ++i) {
|
invokeCallbacks(m_mainArgs);
|
||||||
logFile << *i << '\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Parses the specified command line arguments.
|
||||||
|
* \remarks
|
||||||
|
* - The results are stored in the Argument instances assigned as main arguments and sub arguments.
|
||||||
|
* - In contrast to parseArgs() this method does not check whether constraints are violated and it
|
||||||
|
* does not call any callbacks.
|
||||||
|
* \throws Throws Failure if the specified arguments are invalid.
|
||||||
|
* \sa readArgs()
|
||||||
|
*/
|
||||||
|
void ArgumentParser::readArgs(int argc, const char * const *argv)
|
||||||
|
{
|
||||||
IF_DEBUG_BUILD(verifyArgs(m_mainArgs);)
|
IF_DEBUG_BUILD(verifyArgs(m_mainArgs);)
|
||||||
m_actualArgc = 0;
|
m_actualArgc = 0;
|
||||||
if(argc) {
|
if(argc) {
|
||||||
// the first argument is the executable name
|
// the first argument is the executable name
|
||||||
m_executable = *argv;
|
m_executable = *argv;
|
||||||
|
@ -395,7 +404,7 @@ void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
||||||
currentWordIndex = (--argc ? stringToNumber<unsigned int, string>(*(++argv)) : 0);
|
currentWordIndex = (--argc ? stringToNumber<unsigned int, string>(*(++argv)) : 0);
|
||||||
++argv, --argc;
|
++argv, --argc;
|
||||||
} catch(const ConversionException &) {
|
} catch(const ConversionException &) {
|
||||||
currentWordIndex = argc - 1;
|
currentWordIndex = static_cast<unsigned int>(argc - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,8 +432,6 @@ void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
||||||
m_defaultArg->m_occurrences.emplace_back(0);
|
m_defaultArg->m_occurrences.emplace_back(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkConstraints(m_mainArgs);
|
|
||||||
invokeCallbacks(m_mainArgs);
|
|
||||||
} else {
|
} else {
|
||||||
m_executable = nullptr;
|
m_executable = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ public:
|
||||||
bool denotesOperation() const;
|
bool denotesOperation() const;
|
||||||
void setDenotesOperation(bool denotesOperation);
|
void setDenotesOperation(bool denotesOperation);
|
||||||
void setCallback(CallbackFunction callback);
|
void setCallback(CallbackFunction callback);
|
||||||
void printInfo(std::ostream &os, unsigned char indentionLevel = 0) const;
|
void printInfo(std::ostream &os, unsigned char indentation = 0) const;
|
||||||
const ArgumentVector &subArguments() const;
|
const ArgumentVector &subArguments() const;
|
||||||
void setSubArguments(const ArgumentInitializerList &subArguments);
|
void setSubArguments(const ArgumentInitializerList &subArguments);
|
||||||
void addSubArgument(Argument *arg);
|
void addSubArgument(Argument *arg);
|
||||||
|
@ -211,12 +211,15 @@ public:
|
||||||
void addMainArgument(Argument *argument);
|
void addMainArgument(Argument *argument);
|
||||||
void printHelp(std::ostream &os) const;
|
void printHelp(std::ostream &os) const;
|
||||||
void parseArgs(int argc, const char *const *argv);
|
void parseArgs(int argc, const char *const *argv);
|
||||||
|
void readArgs(int argc, const char *const *argv);
|
||||||
unsigned int actualArgumentCount() const;
|
unsigned int actualArgumentCount() const;
|
||||||
const char *executable() const;
|
const char *executable() const;
|
||||||
UnknownArgumentBehavior unknownArgumentBehavior() const;
|
UnknownArgumentBehavior unknownArgumentBehavior() const;
|
||||||
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior);
|
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior);
|
||||||
Argument *defaultArgument() const;
|
Argument *defaultArgument() const;
|
||||||
void setDefaultArgument(Argument *argument);
|
void setDefaultArgument(Argument *argument);
|
||||||
|
void checkConstraints();
|
||||||
|
void invokeCallbacks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
|
IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
|
||||||
|
@ -767,12 +770,57 @@ inline void ArgumentParser::setDefaultArgument(Argument *argument)
|
||||||
m_defaultArg = argument;
|
m_defaultArg = argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks whether contraints are violated.
|
||||||
|
* \remarks Automatically called by parseArgs().
|
||||||
|
* \throws Throws Failure if constraints are violated.
|
||||||
|
*/
|
||||||
|
inline void ArgumentParser::checkConstraints()
|
||||||
|
{
|
||||||
|
checkConstraints(m_mainArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Invokes all assigned callbacks.
|
||||||
|
* \remarks Automatically called by parseArgs().
|
||||||
|
*/
|
||||||
|
inline void ArgumentParser::invokeCallbacks()
|
||||||
|
{
|
||||||
|
invokeCallbacks(m_mainArgs);
|
||||||
|
}
|
||||||
|
|
||||||
class CPP_UTILITIES_EXPORT HelpArgument : public Argument
|
class CPP_UTILITIES_EXPORT HelpArgument : public Argument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HelpArgument(ArgumentParser &parser);
|
HelpArgument(ArgumentParser &parser);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CPP_UTILITIES_EXPORT OperationArgument : public Argument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OperationArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline OperationArgument::OperationArgument(const char *name, char abbreviation, const char *description, const char *example) :
|
||||||
|
Argument(name, abbreviation, description, example)
|
||||||
|
{
|
||||||
|
setDenotesOperation(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CPP_UTILITIES_EXPORT ConfigValueArgument : public Argument
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConfigValueArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, std::initializer_list<const char *> valueNames = std::initializer_list<const char *>());
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ConfigValueArgument::ConfigValueArgument(const char *name, char abbreviation, const char *description, std::initializer_list<const char *> valueNames) :
|
||||||
|
Argument(name, abbreviation, description)
|
||||||
|
{
|
||||||
|
setCombinable(true);
|
||||||
|
setRequiredValueCount(valueNames.size());
|
||||||
|
setValueNames(valueNames);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H
|
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../global.h"
|
#include "../global.h"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace ApplicationUtilities {
|
namespace ApplicationUtilities {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -24,6 +26,34 @@ void CPP_UTILITIES_EXPORT startConsole();
|
||||||
# define CMD_UTILS_START_CONSOLE
|
# define CMD_UTILS_START_CONSOLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The Indent class allows printing indentation conveniently, eg. cout << Ident(4) << ...
|
||||||
|
*/
|
||||||
|
class CPP_UTILITIES_EXPORT Indentation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Indentation(unsigned char level = 4, char character = ' ') :
|
||||||
|
level(level),
|
||||||
|
character(character)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Indentation operator +(unsigned char level)
|
||||||
|
{
|
||||||
|
return Indentation(this->level + level, character);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char level;
|
||||||
|
char character;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline CPP_UTILITIES_EXPORT std::ostream &operator<< (std::ostream &out, Indentation indentation)
|
||||||
|
{
|
||||||
|
for(unsigned char i = 0; i < indentation.level; ++i) {
|
||||||
|
out << indentation.character;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ApplicationUtilities
|
} // namespace ApplicationUtilities
|
||||||
|
|
||||||
#endif // APPLICATIONUTILITIES_COMMANDLINEUTILS_H
|
#endif // APPLICATIONUTILITIES_COMMANDLINEUTILS_H
|
||||||
|
|
|
@ -102,7 +102,7 @@ inline void eraseDisplay(std::ostream &stream)
|
||||||
|
|
||||||
inline void eraseLine(std::ostream &stream)
|
inline void eraseLine(std::ostream &stream)
|
||||||
{
|
{
|
||||||
stream << "\e[K";
|
stream << "\33[2K";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue