| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 | 
// Qt includes #include <QHash>#include <QStringList>#include <QTextStream>#include <QDebug>// CTK includes#include "ctkCommandLineParser.h"namespace{class CommandLineParserArgumentDescription{public:  CommandLineParserArgumentDescription(    const QString& longArg, const QString& shortArg, QVariant::Type type,    const QString& argHelp, const QVariant& defaultValue, bool ignoreRest)      : LongArg(longArg), ShortArg(shortArg), ArgHelp(argHelp),  IgnoreRest(ignoreRest), NumberOfParametersToProcess(0),  Value(type)  {    if (defaultValue.isValid())    {      Value = defaultValue;    }    switch (type)    {    case QVariant::String:      {        NumberOfParametersToProcess = 1;        RegularExpression = ".*";      }      break;    case QVariant::Bool:      {        NumberOfParametersToProcess = 0;        RegularExpression = "";      }      break;    case QVariant::StringList:      {        NumberOfParametersToProcess = -1;        RegularExpression = ".*";      }      break;    case QVariant::Int:      {        NumberOfParametersToProcess = 1;        RegularExpression = "-?[0-9]+";        ExactMatchFailedMessage = "A negative or positive integer is expected.";      }      break;    default:      ExactMatchFailedMessage = QString("Type %1 not supported.").arg(static_cast<int>(type));    }  }  ~CommandLineParserArgumentDescription(){}  bool addParameter(const QString& value);  QString helpText(int fieldWidth, const char charPad);  QString LongArg;  QString ShortArg;  QString ArgHelp;  bool    IgnoreRest;  int     NumberOfParametersToProcess;  QString RegularExpression;  QString ExactMatchFailedMessage;  QVariant Value;};// --------------------------------------------------------------------------bool CommandLineParserArgumentDescription::addParameter(const QString& value){  if (!RegularExpression.isEmpty())  {    // Validate value    QRegExp regexp(this->RegularExpression);    if (!regexp.exactMatch(value))    {      return false;    }  }  switch (Value.type())  {  case QVariant::String:    {      Value.setValue(value);    }    break;  case QVariant::Bool:    {      Value.setValue(!QString::compare(value, "true", Qt::CaseInsensitive));    }    break;  case QVariant::StringList:    {      if (Value.isNull())      {        QStringList list;        list << value;        Value.setValue(list);      }      else      {        QStringList list = Value.toStringList();        list << value;        Value.setValue(list);      }    }    break;  case QVariant::Int:    {      Value.setValue(value.toInt());    }    break;  default:    return false;  }  return true;}// --------------------------------------------------------------------------QString CommandLineParserArgumentDescription::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;}}// --------------------------------------------------------------------------// ctkCommandLineParser::ctkInternal class// --------------------------------------------------------------------------class ctkCommandLineParser::ctkInternal{public:  ctkInternal():Debug(false),FieldWidth(0){}  ~ctkInternal() { qDeleteAll(ArgumentDescriptionList); }    CommandLineParserArgumentDescription* argumentDescription(const QString& argument);    QList<CommandLineParserArgumentDescription*>          ArgumentDescriptionList;  QHash<QString, CommandLineParserArgumentDescription*> ArgNameToArgumentDescriptionMap;    QStringList UnparsedArguments;   QStringList ProcessedArguments;  QString     ErrorString;  bool        Debug;  int         FieldWidth;};// --------------------------------------------------------------------------// ctkCommandLineParser::ctkInternal methods// --------------------------------------------------------------------------CommandLineParserArgumentDescription*  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;}// --------------------------------------------------------------------------QHash<QString, QVariant> ctkCommandLineParser::parseArguments(const QStringList& arguments,                                                              bool* ok){  // Reset  this->Internal->UnparsedArguments.clear();  this->Internal->ProcessedArguments.clear();  this->Internal->ErrorString.clear();  bool ignoreRest = false;  CommandLineParserArgumentDescription * 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; }            if (ok) *ok = false;            return QHash<QString, QVariant>();            }          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; }            if (ok) *ok = false;            return QHash<QString, QVariant>();            }          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; }            if (ok) *ok = false;            return QHash<QString, QVariant>();            }          }        // 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; }            if (ok) *ok = false;            return QHash<QString, QVariant>();            }          j++;          }        // Update main loop increment        i = i + j;        }      }    else      {      this->Internal->UnparsedArguments << argument;      }    }  if (ok) *ok = true;  QHash<QString, QVariant> parsedArguments;  QListIterator<CommandLineParserArgumentDescription*> it(this->Internal->ArgumentDescriptionList);  while (it.hasNext())  {    QString key;    CommandLineParserArgumentDescription* desc = it.next();    if (!desc->LongArg.isEmpty())    {      key = desc->LongArg;    }    else    {      key = desc->ShortArg;    }    parsedArguments.insert(key, desc->Value);  }  return parsedArguments;}// -------------------------------------------------------------------------QString ctkCommandLineParser::errorString(){  return this->Internal->ErrorString;}// -------------------------------------------------------------------------const QStringList& ctkCommandLineParser::unparsedArguments(){  return this->Internal->UnparsedArguments;}// --------------------------------------------------------------------------void ctkCommandLineParser::addArgument(const QString& longarg, const QString& shortarg,                                       QVariant::Type type, const QString& argHelp,                                       const QVariant& defaultValue, bool ignoreRest){  Q_ASSERT(!defaultValue.isValid() || defaultValue.type() == type);  /* Make sure it's not already added */  bool added = this->Internal->ArgNameToArgumentDescriptionMap.contains(longarg);  Q_ASSERT(!added);  if (added) { return; }  added = this->Internal->ArgNameToArgumentDescriptionMap.contains(shortarg);  Q_ASSERT(!added);  if (added) { return; }  CommandLineParserArgumentDescription* argDesc =    new CommandLineParserArgumentDescription(longarg, shortarg, type,                                             argHelp, defaultValue, ignoreRest);  Q_ASSERT(!(longarg.isEmpty() && shortarg.isEmpty()));  if (longarg.isEmpty() && shortarg.isEmpty()) { return; }  if (!longarg.isEmpty())  {    this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc;    int argWidth = longarg.length() + 7;    if (argWidth > this->Internal->FieldWidth)    {      this->Internal->FieldWidth = argWidth;    }  }  if (!shortarg.isEmpty())  {    this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc;    int argWidth = shortarg.length() + 7;    if (argWidth > this->Internal->FieldWidth)    {      this->Internal->FieldWidth = argWidth;    }  }  this->Internal->ArgumentDescriptionList << argDesc;}// --------------------------------------------------------------------------bool ctkCommandLineParser::setExactMatchRegularExpression(    const QString& argument, const QString& expression, const QString& exactMatchFailedMessage){  CommandLineParserArgumentDescription * argDesc =      this->Internal->argumentDescription(argument);  if (!argDesc)    {    return false;    }  if (argDesc->Value.type() == QVariant::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(CommandLineParserArgumentDescription* 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);}
 |