/*========================================================================= Library: CTK Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.commontk.org/LICENSE Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =========================================================================*/ /*========================================================================= Program: ParaView Module: $RCSfile: vtkCommandOptions.h,v $ Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ // Qt includes #include #include #include #include #include #include #include #include // CTK includes #include #include "ctkVTKCommandOptions.h" // VTKSYS includes #include // -------------------------------------------------------------------------- class ctkVTKCommandOptionsPrivate: public ctkPrivate { public: typedef ctkVTKCommandOptionsPrivate Self; ctkVTKCommandOptionsPrivate(); ~ctkVTKCommandOptionsPrivate(); void cleanArgcArgv(); /// Callback executed when an unknown arguments is parsed static int unknownArgumentHandler(const char* argument, void* call_data); /// If case the --ignore-rest flag has been specified, this method will /// catch the first argument parsed and add it to the ignoredArguments list. /// If not, it will call the virtual method 'wrongArgument(const char* argument)' bool checkForIgnoreRestFlag(const char* argument); /// Callback executed when a deprecated arguments is parsed static int deprecatedArgumentHandler(const char* argument, const char* value, void* call_data); /// Since vtksys::CommandLineArguments will only update char*, returns /// a valid char* pointer that it could use. char** mapQStringPtrToCharPtr(QString* qStringPtr); /// Since vtksys::CommandLineArguments will only update std::vector*, returns /// a valid std::vector* pointer that it could use. std::vector* mapQStringListPtrToStringVectorPtr(QStringList* qStringListPtr); /// If required, sync the updated char* with the corresponding QString* void syncQStringPtrWithCharPtr(); /// If required, sync the updated std::vector with the corresponding QStringList* void syncQStringListPtrWithStringVectorPtr(); vtksys::CommandLineArguments CMD; QString UnknownArgument; QString ErrorMessage; bool HelpSelected; bool DisableSettings; bool IgnoreRest; QStringList IgnoredArguments; int Argc; char** Argv; QPointer Settings; int ProcessType; // GUI, Batch, Daemon, ... QHash QStringPointerToCharPointerMap; QHash*> QStringListPointerToStringVectorPointerMap; }; //----------------------------------------------------------------------------- // ctkVTKCommandOptionsPrivate methods // -------------------------------------------------------------------------- ctkVTKCommandOptionsPrivate::ctkVTKCommandOptionsPrivate() { this->CMD.SetUnknownArgumentCallback(ctkVTKCommandOptionsPrivate::unknownArgumentHandler); this->CMD.SetClientData(this); this->Argc = 0; this->Argv = 0; this->HelpSelected = false; this->DisableSettings = false; this->IgnoreRest = false; } // -------------------------------------------------------------------------- ctkVTKCommandOptionsPrivate::~ctkVTKCommandOptionsPrivate() { this->cleanArgcArgv(); foreach (QString* qStringPtr, this->QStringPointerToCharPointerMap.keys()) { delete this->QStringPointerToCharPointerMap[qStringPtr]; } foreach (QStringList* qStringListPtr, this->QStringListPointerToStringVectorPointerMap.keys()) { delete this->QStringListPointerToStringVectorPointerMap[qStringListPtr]; } } // -------------------------------------------------------------------------- void ctkVTKCommandOptionsPrivate::cleanArgcArgv() { int cc; if (this->Argv) { for (cc = 0; cc < this->Argc; cc++) { delete [] this->Argv[cc]; } delete [] this->Argv; this->Argv = 0; } } //---------------------------------------------------------------------------- int ctkVTKCommandOptionsPrivate::unknownArgumentHandler(const char* argument, void* call_data) { ctkVTKCommandOptionsPrivate* self = static_cast(call_data); if (self) { self->UnknownArgument = QString::fromLatin1(argument); return self->checkForIgnoreRestFlag(argument); } return 0; } //---------------------------------------------------------------------------- bool ctkVTKCommandOptionsPrivate::checkForIgnoreRestFlag(const char* argument) { CTK_P(ctkVTKCommandOptions); if (this->IgnoreRest) { this->IgnoredArguments << QLatin1String(argument); return true; } else { return p->wrongArgument(argument); } } //---------------------------------------------------------------------------- int ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler(const char* argument, const char* , void* call_data) { //qDebug() << "UnknownArgumentHandler: " << argument; ctkVTKCommandOptionsPrivate* self = static_cast(call_data); if (self) { return self->ctk_p()->deprecatedArgument(argument); } return 0; } // -------------------------------------------------------------------------- char** ctkVTKCommandOptionsPrivate::mapQStringPtrToCharPtr(QString* qStringPtr) { Q_ASSERT(!this->QStringPointerToCharPointerMap.contains(qStringPtr)); char** charPtr = new char*; // Create a new pointer *charPtr = 0; // Initialize to 0 this->QStringPointerToCharPointerMap[qStringPtr] = charPtr; return charPtr; } // -------------------------------------------------------------------------- std::vector* ctkVTKCommandOptionsPrivate::mapQStringListPtrToStringVectorPtr(QStringList* qStringListPtr) { Q_ASSERT(!this->QStringListPointerToStringVectorPointerMap.contains(qStringListPtr)); std::vector* vectorPtr = new std::vector(); // Create a new vector this->QStringListPointerToStringVectorPointerMap[qStringListPtr] = vectorPtr; return vectorPtr; } // -------------------------------------------------------------------------- void ctkVTKCommandOptionsPrivate::syncQStringPtrWithCharPtr() { foreach(QString* qStringPtr, this->QStringPointerToCharPointerMap.keys()) { char** charPtr = this->QStringPointerToCharPointerMap[qStringPtr]; Q_ASSERT(charPtr); // Update QString only if the content pointed by charPtr is valid if (*charPtr) { qStringPtr->clear(); qStringPtr->append(QLatin1String(*charPtr)); } } } // -------------------------------------------------------------------------- void ctkVTKCommandOptionsPrivate::syncQStringListPtrWithStringVectorPtr() { foreach(QStringList* qStringListPtr, this->QStringListPointerToStringVectorPointerMap.keys()) { std::vector* vectorPtr = this->QStringListPointerToStringVectorPointerMap[qStringListPtr]; Q_ASSERT(vectorPtr); // Update QString only if vectorPtr is not empty if (vectorPtr->size() > 0) { qStringListPtr->clear(); QStringList convertedVector; ctkUtils::stlVectorToQList(*vectorPtr, convertedVector); qStringListPtr->append(convertedVector); } } } //----------------------------------------------------------------------------- // ctkVTKCommandOptions methods // -------------------------------------------------------------------------- ctkVTKCommandOptions::ctkVTKCommandOptions(QSettings* _settings) { CTK_INIT_PRIVATE(ctkVTKCommandOptions); Q_ASSERT(_settings); CTK_D(ctkVTKCommandOptions); d->Settings = _settings; } //---------------------------------------------------------------------------- ctkVTKCommandOptions::~ctkVTKCommandOptions() { } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::printAdditionalInfo() { CTK_D(ctkVTKCommandOptions); qDebug() << "ctkVTKCommandOptions:" << this << endl << " HelpSelected:" << this->helpSelected() << endl << " DisableSettings:" << d->DisableSettings << endl << " IgnoreRest:" << d->IgnoreRest << endl << " IgnoredArguments:" << d->IgnoredArguments; } //---------------------------------------------------------------------------- CTK_GET_CXX(ctkVTKCommandOptions, QString, errorMessage, ErrorMessage); CTK_GET_CXX(ctkVTKCommandOptions, QString, unknownArgument, UnknownArgument); CTK_GET_CXX(ctkVTKCommandOptions, bool, helpSelected, HelpSelected); CTK_GET_CXX(ctkVTKCommandOptions, bool, disableSettings, DisableSettings); CTK_GET_CXX(ctkVTKCommandOptions, QSettings*, settings, Settings); CTK_GET_CXX(ctkVTKCommandOptions, bool, ignoreRest, IgnoreRest); CTK_GET_CXX(ctkVTKCommandOptions, QStringList, ignoredArguments, IgnoredArguments); //---------------------------------------------------------------------------- CTK_GET_CXX(ctkVTKCommandOptions, int, processType, ProcessType); CTK_SET_CXX(ctkVTKCommandOptions, int, setProcessType, ProcessType); //---------------------------------------------------------------------------- void ctkVTKCommandOptions::initialize() { } //---------------------------------------------------------------------------- QString ctkVTKCommandOptions::help() { CTK_D(ctkVTKCommandOptions); d->CMD.SetLineLength(300); return QLatin1String(d->CMD.GetHelp()); } //---------------------------------------------------------------------------- bool ctkVTKCommandOptions::postProcess(int, const char* const*) { return true; } //---------------------------------------------------------------------------- bool ctkVTKCommandOptions::parse(int argc, const char* const argv[]) { CTK_D(ctkVTKCommandOptions); d->CMD.Initialize(argc, argv); this->initialize(); this->addBooleanArgument("--help", "/?", &d->HelpSelected, "Displays available command line arguments."); this->addBooleanArgument("--disable-settings", 0, &d->DisableSettings, "Start application ignoring user settings."); this->addBooleanArgument("--ignore-rest", "--", &d->IgnoreRest, "Ignores the rest of the labeled arguments following this flag."); // Get options from the command line bool res1 = d->CMD.Parse(); bool res2 = this->postProcess(argc, argv); //qDebug() << "Res1:" << res1 << ", Res2:" << res2; d->cleanArgcArgv(); d->CMD.GetRemainingArguments(&d->Argc, &d->Argv); if (d->DisableSettings) { this->disableCurrentSettings(); } d->syncQStringPtrWithCharPtr(); d->syncQStringListPtrWithStringVectorPtr(); // Since CommandLineArguments include arg0 in the list // of remaining arguments, let's create a temporary list and remove it. QStringList _remaingingArguments = this->remainingArguments(); _remaingingArguments.removeFirst(); // Update ignored arguments list d->IgnoredArguments << _remaingingArguments; return res1 && res2; } //---------------------------------------------------------------------------- QStringList ctkVTKCommandOptions::remainingArguments() { CTK_D(ctkVTKCommandOptions); QStringList tmp; for(int i=0; i < d->Argc; ++i) { tmp << d->Argv[i]; } return tmp; } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::remainingArguments(int* argc, char*** argv) { CTK_D(ctkVTKCommandOptions); *argc = d->Argc; *argv = d->Argv; } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::addDeprecatedArgument(const char* longarg, const char* shortarg, const char* arghelp, int type) { CTK_D(ctkVTKCommandOptions); // If it is for settings or not for the current process do nothing if((type & ctkVTKCommandOptions::QSETTINGS_ONLY) || !(type & d->ProcessType || type == ctkVTKCommandOptions::ALL)) { return; } // Add a callback for the deprecated argument handling d->CMD.AddCallback(longarg, vtksys::CommandLineArguments::NO_ARGUMENT, ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler, this, arghelp); if(shortarg) { d->CMD.AddCallback(shortarg, vtksys::CommandLineArguments::NO_ARGUMENT, ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler, this, arghelp); } } //---------------------------------------------------------------------------- bool ctkVTKCommandOptions::deprecatedArgument(const char* argument) { CTK_D(ctkVTKCommandOptions); d->ErrorMessage = QString(" %1").arg(d->CMD.GetHelp(argument)); return false; } //---------------------------------------------------------------------------- bool ctkVTKCommandOptions::wrongArgument(const char* argument) { Q_UNUSED(argument); return false; } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::addBooleanArgument(const char* longarg, const char* shortarg, bool* var, const char* arghelp, bool defaultValue, int type) { CTK_D(ctkVTKCommandOptions); // Attempt to read from settings only if longarg is different from '--disable-settings'. if (QLatin1String(longarg) != "--disable-settings") { *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toBool(); if(type & ctkVTKCommandOptions::QSETTINGS_ONLY) { return; } } // If the process type matches then add the argument to the command line if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL) { d->CMD.AddBooleanArgument(longarg, var, arghelp); if (shortarg) { d->CMD.AddBooleanArgument(shortarg, var, longarg); } } } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg, QString* var, const char* arghelp, const QString& defaultValue, int type) { CTK_D(ctkVTKCommandOptions); *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toString(); if(type & ctkVTKCommandOptions::QSETTINGS_ONLY) { return; } if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL) { char ** charstar = d->mapQStringPtrToCharPtr(var); typedef vtksys::CommandLineArguments argT; d->CMD.AddArgument(longarg, argT::EQUAL_ARGUMENT, charstar, arghelp); if ( shortarg ) { d->CMD.AddArgument(shortarg, argT::EQUAL_ARGUMENT, charstar, longarg); } } } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg, QStringList* var, const char* arghelp, const QStringList& defaultValue, int type) { CTK_D(ctkVTKCommandOptions); *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toStringList(); if(type & ctkVTKCommandOptions::QSETTINGS_ONLY) { return; } if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL) { std::vector* vectorPtr = d->mapQStringListPtrToStringVectorPtr(var); typedef vtksys::CommandLineArguments argT; d->CMD.AddArgument(longarg, argT::MULTI_ARGUMENT, vectorPtr, arghelp); if (shortarg) { d->CMD.AddArgument(shortarg, argT::MULTI_ARGUMENT, vectorPtr, longarg); } } } //---------------------------------------------------------------------------- void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg, int* var, const char* arghelp, int defaultValue, int type) { CTK_D(ctkVTKCommandOptions); *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toInt(); if(type & ctkVTKCommandOptions::QSETTINGS_ONLY) { return; } if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL) { typedef vtksys::CommandLineArguments argT; d->CMD.AddArgument(longarg, argT::EQUAL_ARGUMENT, var, arghelp); if (shortarg) { d->CMD.AddArgument(shortarg, argT::EQUAL_ARGUMENT, var, longarg); } } } //---------------------------------------------------------------------------- int ctkVTKCommandOptions::indexOfLastParsedArgument() { CTK_D(ctkVTKCommandOptions); return d->CMD.GetLastArgument(); }