123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- // Qt includes
- #include <QHash>
- #include <QStringList>
- #include <QTextStream>
- #include <QDebug>
- // CTK includes
- #include "ctkCommandLineParser.h"
- namespace
- {
- class CommandLineParserArgumentDescriptionBase
- {
- public:
- CommandLineParserArgumentDescriptionBase(
- const char* longArg, const char* shortArg, const QString& argHelp, bool ignoreRest)
- {
- this->LongArg = QLatin1String(longArg);
- this->ShortArg = QLatin1String(shortArg);
- this->ArgHelp = argHelp;
- this->IgnoreRest = ignoreRest;
- this->NumberOfParametersToProcess = 0;
- }
- virtual bool addParameter(const QString& value) = 0;
- QString helpText(int fieldWidth, const char charPad);
- QString LongArg;
- QString ShortArg;
- QString ArgHelp;
- bool IgnoreRest;
- int NumberOfParametersToProcess;
- QString RegularExpression;
- QString ExactMatchFailedMessage;
- QString ArgumentType;
- };
- // --------------------------------------------------------------------------
- QString CommandLineParserArgumentDescriptionBase::helpText(int fieldWidth, const char charPad)
- {
- QString text;
- QTextStream stream(&text);
- stream.setFieldAlignment(QTextStream::AlignLeft);
- stream.setPadChar(charPad);
- if (this->LongArg.isEmpty() && !this->ArgHelp.isEmpty())
- {
- stream.setFieldWidth(fieldWidth);
- }
- if (!this->ShortArg.isEmpty())
- {
- stream << QString(" %1").arg(this->ShortArg);
- if(!this->LongArg.isEmpty())
- {
- stream << "\n";
- }
- }
- if (!this->LongArg.isEmpty())
- {
- if(!this->ArgHelp.isEmpty())
- {
- stream.setFieldWidth(fieldWidth);
- }
- stream << QString(" %1").arg(this->LongArg);
- }
- stream.setFieldWidth(0);
- stream << this->ArgHelp << "\n";
- return text;
- }
- #define CommandLineParserArgumentDescription_class(_NAME, _TYPE, \
- _NUMBEROFPARAMTOPROCESS, \
- _REGEXP, _EXACTMACTHERRORMSG) \
- class CommandLineParser##_NAME##ArgumentDescription: \
- public CommandLineParserArgumentDescriptionBase \
- { \
- public: \
- CommandLineParser##_NAME##ArgumentDescription( \
- const char* longArg, const char* shortArg, _TYPE * variable, \
- const QString& argHelp, const _TYPE& defaultValue, \
- bool ignoreRest): \
- CommandLineParserArgumentDescriptionBase(longArg , shortArg, argHelp, ignoreRest) \
- { \
- this->Variable = variable; \
- this->DefaultValue = defaultValue; \
- this->NumberOfParametersToProcess = _NUMBEROFPARAMTOPROCESS; \
- this->RegularExpression = _REGEXP; \
- this->ArgumentType = #_TYPE; \
- } \
- virtual bool addParameter(const QString& value); \
- _TYPE* Variable; \
- _TYPE DefaultValue; \
- };
- CommandLineParserArgumentDescription_class(String, QString, 1, ".*", "");
- CommandLineParserArgumentDescription_class(Boolean, bool, 0, "", "");
- CommandLineParserArgumentDescription_class(StringList, QStringList, -1, ".*", "");
- CommandLineParserArgumentDescription_class(Integer, int, 1, "-?[0-9]+",
- "A negative or positive integer is expected.");
- #undef CommandLineParserArgumentDescription_class
- // --------------------------------------------------------------------------
- bool CommandLineParserStringArgumentDescription::addParameter(const QString& value)
- {
- // Validate value
- QRegExp regexp(this->RegularExpression);
- if (!regexp.exactMatch(value))
- {
- return false;
- }
- (*this->Variable).clear();
- (*this->Variable).append(value);
- return true;
- }
- // --------------------------------------------------------------------------
- bool CommandLineParserBooleanArgumentDescription::addParameter(const QString& value)
- {
- *this->Variable = (value == "true");
- return true;
- }
- // --------------------------------------------------------------------------
- bool CommandLineParserStringListArgumentDescription::addParameter(const QString& value)
- {
- // Validate value
- QRegExp regexp(this->RegularExpression);
- if (!regexp.exactMatch(value))
- {
- return false;
- }
- *this->Variable << value;
- return true;
- }
- // --------------------------------------------------------------------------
- bool CommandLineParserIntegerArgumentDescription::addParameter(const QString& value)
- {
- // Validate value
- QRegExp regexp(this->RegularExpression);
- if (!regexp.exactMatch(value))
- {
- return false;
- }
- *this->Variable = value.toInt();
- return true;
- }
- }
- // --------------------------------------------------------------------------
- // ctkCommandLineParser::ctkInternal class
- // --------------------------------------------------------------------------
- class ctkCommandLineParser::ctkInternal
- {
- public:
- ctkInternal():Debug(false),FieldWidth(0){}
-
- CommandLineParserArgumentDescriptionBase* argumentDescription(const QString& argument);
-
- QList<CommandLineParserArgumentDescriptionBase*> ArgumentDescriptionList;
- QHash<QString, CommandLineParserArgumentDescriptionBase*> ArgNameToArgumentDescriptionMap;
-
- #define ctkCommandLineParser_ctkInternal_declare_map(_NAME) \
- QHash<QString, CommandLineParser##_NAME##ArgumentDescription*> \
- LongArgTo##_NAME##ArgumentDescriptionMap; \
- QHash<QString, CommandLineParser##_NAME##ArgumentDescription*> \
- ShortArgTo##_NAME##ArgumentDescriptionMap;
-
- ctkCommandLineParser_ctkInternal_declare_map(String);
- ctkCommandLineParser_ctkInternal_declare_map(Boolean);
- ctkCommandLineParser_ctkInternal_declare_map(StringList);
- ctkCommandLineParser_ctkInternal_declare_map(Integer);
-
- #undef ctkCommandLineParser_ctkInternal_declare_map
-
- QStringList UnparsedArguments;
- QStringList ProcessedArguments;
- QString ErrorString;
- bool Debug;
- int FieldWidth;
- };
- // --------------------------------------------------------------------------
- // ctkCommandLineParser::ctkInternal methods
- // --------------------------------------------------------------------------
- CommandLineParserArgumentDescriptionBase*
- ctkCommandLineParser::ctkInternal::argumentDescription(const QString& argument)
- {
- if (this->ArgNameToArgumentDescriptionMap.contains(argument))
- {
- return this->ArgNameToArgumentDescriptionMap[argument];
- }
- return 0;
- }
- // --------------------------------------------------------------------------
- // ctkCommandLineParser methods
- // --------------------------------------------------------------------------
- ctkCommandLineParser::ctkCommandLineParser()
- {
- this->Internal = new ctkInternal();
- }
- // --------------------------------------------------------------------------
- ctkCommandLineParser::~ctkCommandLineParser()
- {
- delete this->Internal;
- }
- // --------------------------------------------------------------------------
- bool ctkCommandLineParser::parseArguments(const QStringList& arguments)
- {
- // Reset
- this->Internal->UnparsedArguments.clear();
- this->Internal->ProcessedArguments.clear();
- this->Internal->ErrorString.clear();
- bool ignoreRest = false;
- CommandLineParserArgumentDescriptionBase * currentArgDesc = 0;
- for(int i = 1; i < arguments.size(); ++i)
- {
- QString argument = arguments.at(i);
- if (this->Internal->Debug) { qDebug() << "Processing" << argument; }
- // should argument be ignored ?
- if (ignoreRest)
- {
- this->Internal->UnparsedArguments << argument;
- continue;
- }
- // Skip if argument has already been parsed ...
- if (this->Internal->ProcessedArguments.contains(argument))
- {
- qDebug() << "Skipping argument" << argument << " - Already processed !";
- continue;
- }
- // Retrieve corresponding argument description
- currentArgDesc = this->Internal->argumentDescription(argument);
- // Is there a corresponding argument description ?
- if (currentArgDesc)
- {
- this->Internal->ProcessedArguments << currentArgDesc->ShortArg << currentArgDesc->LongArg;
- int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess;
- ignoreRest = currentArgDesc->IgnoreRest;
- // Is the number of parameters associated with the argument being processed known ?
- if (numberOfParametersToProcess == 0)
- {
- currentArgDesc->addParameter("true");
- }
- else if (numberOfParametersToProcess > 0)
- {
- QString missingParameterError =
- "Argument %1 has %2 value(s) associated whereas exacly %3 are expected.";
- for(int j=1; j <= numberOfParametersToProcess; ++j)
- {
- if (i + j >= arguments.size())
- {
- this->Internal->ErrorString =
- missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
- if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
- return false;
- }
- QString parameter = arguments.at(i + j);
- if (this->Internal->Debug)
- {
- qDebug() << "Processing parameter" << j << ", value:" << parameter;
- }
- if (this->argumentAdded(parameter))
- {
- this->Internal->ErrorString =
- missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess);
- if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
- return false;
- }
- if (!currentArgDesc->addParameter(parameter))
- {
- this->Internal->ErrorString = QString(
- "Value(s) associated with argument %1 are incorrect. %2").
- arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
- if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
- return false;
- }
- }
- // Update main loop increment
- i = i + numberOfParametersToProcess;
- }
- else if (numberOfParametersToProcess == -1)
- {
- if (this->Internal->Debug)
- {
- qDebug() << "Proccessing StringList ...";
- }
- int j = 1;
- while(j + i < arguments.size())
- {
- if (this->argumentAdded(arguments.at(j + i)))
- {
- if (this->Internal->Debug)
- {
- qDebug() << "No more parameter for" << argument;
- }
- break;
- }
- QString parameter = arguments.at(j + i);
- if (this->Internal->Debug)
- {
- qDebug() << "Processing parameter" << j << ", value:" << parameter;
- }
- if (!currentArgDesc->addParameter(parameter))
- {
- this->Internal->ErrorString = QString(
- "Value(s) associated with argument %1 are incorrect. %2").
- arg(argument).arg(currentArgDesc->ExactMatchFailedMessage);
- if (this->Internal->Debug) { qDebug() << this->Internal->ErrorString; }
- return false;
- }
- j++;
- }
- // Update main loop increment
- i = i + j;
- }
- }
- else
- {
- this->Internal->UnparsedArguments << argument;
- }
- }
- return true;
- }
- // -------------------------------------------------------------------------
- QString ctkCommandLineParser::errorString()
- {
- return this->Internal->ErrorString;
- }
- // -------------------------------------------------------------------------
- const QStringList& ctkCommandLineParser::unparsedArguments()
- {
- return this->Internal->UnparsedArguments;
- }
- // -------------------------------------------------------------------------
- #define ctkCommandLineParser_addArgument_cxx_core(_NAME, _TYPE) \
- /* Make sure it's not already added */ \
- bool added = this->Internal->LongArgTo##_NAME##ArgumentDescriptionMap.contains(longarg); \
- Q_ASSERT(!added); \
- if (added) { return; } \
- \
- added = this->Internal->ShortArgTo##_NAME##ArgumentDescriptionMap.contains(shortarg); \
- Q_ASSERT(!added); \
- if (added) { return; } \
- \
- CommandLineParser##_NAME##ArgumentDescription * argDesc = \
- new CommandLineParser##_NAME##ArgumentDescription(longarg, shortarg, var, \
- argHelp, defaultValue, ignoreRest); \
- \
- Q_ASSERT(!(longarg == 0 && shortarg == 0)); \
- if (longarg == 0 && shortarg == 0) { return; } \
- if (longarg != 0) \
- { \
- this->Internal->LongArgTo##_NAME##ArgumentDescriptionMap[longarg] = argDesc; \
- int argWidth = QString(longarg).length() + 7; \
- if (argWidth > this->Internal->FieldWidth) \
- { \
- this->Internal->FieldWidth = argWidth; \
- } \
- } \
- if (shortarg != 0) \
- { \
- this->Internal->ShortArgTo##_NAME##ArgumentDescriptionMap[shortarg] = argDesc; \
- int argWidth = QString(shortarg).length() + 7; \
- if (argWidth > this->Internal->FieldWidth) \
- { \
- this->Internal->FieldWidth = argWidth; \
- } \
- } \
- this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; \
- this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; \
- this->Internal->ArgumentDescriptionList << argDesc;
- // -------------------------------------------------------------------------
- #define ctkCommandLineParser_addArgument_cxx(_NAME, _TYPE) \
- void ctkCommandLineParser::add##_NAME##Argument(const char* longarg, \
- const char* shortarg, _TYPE* var, const QString& argHelp, const _TYPE& defaultValue, \
- bool ignoreRest) \
- { \
- ctkCommandLineParser_addArgument_cxx_core(_NAME, _TYPE); \
- }
- // -------------------------------------------------------------------------
- #define ctkCommandLineParser_addArgument_cxx_without_ignore_rest(_NAME, _TYPE) \
- void ctkCommandLineParser::add##_NAME##Argument(const char* longarg, \
- const char* shortarg, _TYPE* var, const QString& argHelp, const _TYPE& defaultValue) \
- { \
- bool ignoreRest = false; \
- ctkCommandLineParser_addArgument_cxx_core(_NAME, _TYPE); \
- }
- // --------------------------------------------------------------------------
- ctkCommandLineParser_addArgument_cxx(String, QString);
- ctkCommandLineParser_addArgument_cxx(Boolean, bool);
- ctkCommandLineParser_addArgument_cxx_without_ignore_rest(StringList, QStringList);
- ctkCommandLineParser_addArgument_cxx(Integer, int);
- #undef ctkCommandLineParser_addArgument_cxx
- // --------------------------------------------------------------------------
- bool ctkCommandLineParser::setExactMatchRegularExpression(
- const QString& argument, const QString& expression, const QString& exactMatchFailedMessage)
- {
- CommandLineParserArgumentDescriptionBase * argDesc =
- this->Internal->argumentDescription(argument);
- if (!argDesc)
- {
- return false;
- }
- if (argDesc->ArgumentType == "bool")
- {
- return false;
- }
- argDesc->RegularExpression = expression;
- argDesc->ExactMatchFailedMessage = exactMatchFailedMessage;
- return true;
- }
- // --------------------------------------------------------------------------
- QString ctkCommandLineParser::helpText(const char charPad)
- {
- QString text;
- QTextStream stream(&text);
- // Loop over argument descriptions
- foreach(CommandLineParserArgumentDescriptionBase* argDesc,
- this->Internal->ArgumentDescriptionList)
- {
- stream << argDesc->helpText(this->Internal->FieldWidth, charPad);
- }
- return text;
- }
- // --------------------------------------------------------------------------
- bool ctkCommandLineParser::argumentAdded(const QString& argument)
- {
- return this->Internal->ArgNameToArgumentDescriptionMap.contains(argument);
- }
- // --------------------------------------------------------------------------
- bool ctkCommandLineParser::argumentParsed(const QString& argument)
- {
- return this->Internal->ProcessedArguments.contains(argument);
- }
|