ctkVTKCommandOptions.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 2010 Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. /*=========================================================================
  15. Program: ParaView
  16. Module: $RCSfile: vtkCommandOptions.h,v $
  17. Copyright (c) Kitware, Inc.
  18. All rights reserved.
  19. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
  20. This software is distributed WITHOUT ANY WARRANTY; without even
  21. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  22. PURPOSE. See the above copyright notice for more information.
  23. =========================================================================*/
  24. // Qt includes
  25. #include <QDebug>
  26. #include <QString>
  27. #include <QLatin1String>
  28. #include <QSettings>
  29. #include <QHash>
  30. #include <QList>
  31. #include <QPointer>
  32. #include <QStringList>
  33. // CTK includes
  34. #include <ctkUtils.h>
  35. #include "ctkVTKCommandOptions.h"
  36. // VTKSYS includes
  37. #include <vtksys/CommandLineArguments.hxx>
  38. // --------------------------------------------------------------------------
  39. class ctkVTKCommandOptionsPrivate: public ctkPrivate<ctkVTKCommandOptions>
  40. {
  41. public:
  42. typedef ctkVTKCommandOptionsPrivate Self;
  43. ctkVTKCommandOptionsPrivate();
  44. ~ctkVTKCommandOptionsPrivate();
  45. void cleanArgcArgv();
  46. /// Callback executed when an unknown arguments is parsed
  47. static int unknownArgumentHandler(const char* argument, void* call_data);
  48. /// If case the --ignore-rest flag has been specified, this method will
  49. /// catch the first argument parsed and add it to the ignoredArguments list.
  50. /// If not, it will call the virtual method 'wrongArgument(const char* argument)'
  51. bool checkForIgnoreRestFlag(const char* argument);
  52. /// Callback executed when a deprecated arguments is parsed
  53. static int deprecatedArgumentHandler(const char* argument, const char* value, void* call_data);
  54. /// Since vtksys::CommandLineArguments will only update char*, returns
  55. /// a valid char* pointer that it could use.
  56. char** mapQStringPtrToCharPtr(QString* qStringPtr);
  57. /// Since vtksys::CommandLineArguments will only update std::vector<std::string>*, returns
  58. /// a valid std::vector<std::string>* pointer that it could use.
  59. std::vector<std::string>* mapQStringListPtrToStringVectorPtr(QStringList* qStringListPtr);
  60. /// If required, sync the updated char* with the corresponding QString*
  61. void syncQStringPtrWithCharPtr();
  62. /// If required, sync the updated std::vector<std::string> with the corresponding QStringList*
  63. void syncQStringListPtrWithStringVectorPtr();
  64. vtksys::CommandLineArguments CMD;
  65. QString UnknownArgument;
  66. QString ErrorMessage;
  67. bool HelpSelected;
  68. bool DisableSettings;
  69. bool IgnoreRest;
  70. QStringList IgnoredArguments;
  71. int Argc;
  72. char** Argv;
  73. QPointer<QSettings> Settings;
  74. int ProcessType; // GUI, Batch, Daemon, ...
  75. QHash<QString*, char**> QStringPointerToCharPointerMap;
  76. QHash<QStringList*, std::vector<std::string>*> QStringListPointerToStringVectorPointerMap;
  77. };
  78. //-----------------------------------------------------------------------------
  79. // ctkVTKCommandOptionsPrivate methods
  80. // --------------------------------------------------------------------------
  81. ctkVTKCommandOptionsPrivate::ctkVTKCommandOptionsPrivate()
  82. {
  83. this->CMD.SetUnknownArgumentCallback(ctkVTKCommandOptionsPrivate::unknownArgumentHandler);
  84. this->CMD.SetClientData(this);
  85. this->Argc = 0;
  86. this->Argv = 0;
  87. this->HelpSelected = false;
  88. this->DisableSettings = false;
  89. this->IgnoreRest = false;
  90. }
  91. // --------------------------------------------------------------------------
  92. ctkVTKCommandOptionsPrivate::~ctkVTKCommandOptionsPrivate()
  93. {
  94. this->cleanArgcArgv();
  95. foreach (QString* qStringPtr, this->QStringPointerToCharPointerMap.keys())
  96. {
  97. delete this->QStringPointerToCharPointerMap[qStringPtr];
  98. }
  99. foreach (QStringList* qStringListPtr, this->QStringListPointerToStringVectorPointerMap.keys())
  100. {
  101. delete this->QStringListPointerToStringVectorPointerMap[qStringListPtr];
  102. }
  103. }
  104. // --------------------------------------------------------------------------
  105. void ctkVTKCommandOptionsPrivate::cleanArgcArgv()
  106. {
  107. int cc;
  108. if (this->Argv)
  109. {
  110. for (cc = 0; cc < this->Argc; cc++)
  111. {
  112. delete [] this->Argv[cc];
  113. }
  114. delete [] this->Argv;
  115. this->Argv = 0;
  116. }
  117. }
  118. //----------------------------------------------------------------------------
  119. int ctkVTKCommandOptionsPrivate::unknownArgumentHandler(const char* argument,
  120. void* call_data)
  121. {
  122. ctkVTKCommandOptionsPrivate* self =
  123. static_cast<ctkVTKCommandOptionsPrivate*>(call_data);
  124. if (self)
  125. {
  126. self->UnknownArgument = QString::fromLatin1(argument);
  127. return self->checkForIgnoreRestFlag(argument);
  128. }
  129. return 0;
  130. }
  131. //----------------------------------------------------------------------------
  132. bool ctkVTKCommandOptionsPrivate::checkForIgnoreRestFlag(const char* argument)
  133. {
  134. CTK_P(ctkVTKCommandOptions);
  135. if (this->IgnoreRest)
  136. {
  137. this->IgnoredArguments << QLatin1String(argument);
  138. return true;
  139. }
  140. else
  141. {
  142. return p->wrongArgument(argument);
  143. }
  144. }
  145. //----------------------------------------------------------------------------
  146. int ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler(const char* argument,
  147. const char* , void* call_data)
  148. {
  149. //qDebug() << "UnknownArgumentHandler: " << argument;
  150. ctkVTKCommandOptionsPrivate* self = static_cast<ctkVTKCommandOptionsPrivate*>(call_data);
  151. if (self)
  152. {
  153. return self->ctk_p()->deprecatedArgument(argument);
  154. }
  155. return 0;
  156. }
  157. // --------------------------------------------------------------------------
  158. char** ctkVTKCommandOptionsPrivate::mapQStringPtrToCharPtr(QString* qStringPtr)
  159. {
  160. Q_ASSERT(!this->QStringPointerToCharPointerMap.contains(qStringPtr));
  161. char** charPtr = new char*; // Create a new pointer
  162. *charPtr = 0; // Initialize to 0
  163. this->QStringPointerToCharPointerMap[qStringPtr] = charPtr;
  164. return charPtr;
  165. }
  166. // --------------------------------------------------------------------------
  167. std::vector<std::string>*
  168. ctkVTKCommandOptionsPrivate::mapQStringListPtrToStringVectorPtr(QStringList* qStringListPtr)
  169. {
  170. Q_ASSERT(!this->QStringListPointerToStringVectorPointerMap.contains(qStringListPtr));
  171. std::vector<std::string>* vectorPtr = new std::vector<std::string>(); // Create a new vector
  172. this->QStringListPointerToStringVectorPointerMap[qStringListPtr] = vectorPtr;
  173. return vectorPtr;
  174. }
  175. // --------------------------------------------------------------------------
  176. void ctkVTKCommandOptionsPrivate::syncQStringPtrWithCharPtr()
  177. {
  178. foreach(QString* qStringPtr, this->QStringPointerToCharPointerMap.keys())
  179. {
  180. char** charPtr = this->QStringPointerToCharPointerMap[qStringPtr];
  181. Q_ASSERT(charPtr);
  182. // Update QString only if the content pointed by charPtr is valid
  183. if (*charPtr)
  184. {
  185. qStringPtr->clear();
  186. qStringPtr->append(QLatin1String(*charPtr));
  187. }
  188. }
  189. }
  190. // --------------------------------------------------------------------------
  191. void ctkVTKCommandOptionsPrivate::syncQStringListPtrWithStringVectorPtr()
  192. {
  193. foreach(QStringList* qStringListPtr, this->QStringListPointerToStringVectorPointerMap.keys())
  194. {
  195. std::vector<std::string>* vectorPtr =
  196. this->QStringListPointerToStringVectorPointerMap[qStringListPtr];
  197. Q_ASSERT(vectorPtr);
  198. // Update QString only if vectorPtr is not empty
  199. if (vectorPtr->size() > 0)
  200. {
  201. qStringListPtr->clear();
  202. QStringList convertedVector;
  203. ctk::stlVectorToQList(*vectorPtr, convertedVector);
  204. qStringListPtr->append(convertedVector);
  205. }
  206. }
  207. }
  208. //-----------------------------------------------------------------------------
  209. // ctkVTKCommandOptions methods
  210. // --------------------------------------------------------------------------
  211. ctkVTKCommandOptions::ctkVTKCommandOptions(QSettings* _settings)
  212. {
  213. CTK_INIT_PRIVATE(ctkVTKCommandOptions);
  214. Q_ASSERT(_settings);
  215. CTK_D(ctkVTKCommandOptions);
  216. d->Settings = _settings;
  217. }
  218. //----------------------------------------------------------------------------
  219. ctkVTKCommandOptions::~ctkVTKCommandOptions()
  220. {
  221. }
  222. //----------------------------------------------------------------------------
  223. void ctkVTKCommandOptions::printAdditionalInfo()
  224. {
  225. CTK_D(ctkVTKCommandOptions);
  226. qDebug() << "ctkVTKCommandOptions:" << this << endl
  227. << " HelpSelected:" << this->helpSelected() << endl
  228. << " DisableSettings:" << d->DisableSettings << endl
  229. << " IgnoreRest:" << d->IgnoreRest << endl
  230. << " IgnoredArguments:" << d->IgnoredArguments;
  231. }
  232. //----------------------------------------------------------------------------
  233. CTK_GET_CXX(ctkVTKCommandOptions, QString, errorMessage, ErrorMessage);
  234. CTK_GET_CXX(ctkVTKCommandOptions, QString, unknownArgument, UnknownArgument);
  235. CTK_GET_CXX(ctkVTKCommandOptions, bool, helpSelected, HelpSelected);
  236. CTK_GET_CXX(ctkVTKCommandOptions, bool, disableSettings, DisableSettings);
  237. CTK_GET_CXX(ctkVTKCommandOptions, QSettings*, settings, Settings);
  238. CTK_GET_CXX(ctkVTKCommandOptions, bool, ignoreRest, IgnoreRest);
  239. CTK_GET_CXX(ctkVTKCommandOptions, QStringList, ignoredArguments, IgnoredArguments);
  240. //----------------------------------------------------------------------------
  241. CTK_GET_CXX(ctkVTKCommandOptions, int, processType, ProcessType);
  242. CTK_SET_CXX(ctkVTKCommandOptions, int, setProcessType, ProcessType);
  243. //----------------------------------------------------------------------------
  244. void ctkVTKCommandOptions::initialize()
  245. {
  246. }
  247. //----------------------------------------------------------------------------
  248. QString ctkVTKCommandOptions::help()
  249. {
  250. CTK_D(ctkVTKCommandOptions);
  251. d->CMD.SetLineLength(300);
  252. return QLatin1String(d->CMD.GetHelp());
  253. }
  254. //----------------------------------------------------------------------------
  255. bool ctkVTKCommandOptions::postProcess(int, const char* const*)
  256. {
  257. return true;
  258. }
  259. //----------------------------------------------------------------------------
  260. bool ctkVTKCommandOptions::parse(int argc, const char* const argv[])
  261. {
  262. CTK_D(ctkVTKCommandOptions);
  263. d->CMD.Initialize(argc, argv);
  264. this->initialize();
  265. this->addBooleanArgument("--help", "/?", &d->HelpSelected,
  266. "Displays available command line arguments.");
  267. this->addBooleanArgument("--disable-settings", 0, &d->DisableSettings,
  268. "Start application ignoring user settings.");
  269. this->addBooleanArgument("--ignore-rest", "--", &d->IgnoreRest,
  270. "Ignores the rest of the labeled arguments following this flag.");
  271. // Get options from the command line
  272. bool res1 = d->CMD.Parse();
  273. bool res2 = this->postProcess(argc, argv);
  274. //qDebug() << "Res1:" << res1 << ", Res2:" << res2;
  275. d->cleanArgcArgv();
  276. d->CMD.GetRemainingArguments(&d->Argc, &d->Argv);
  277. if (d->DisableSettings)
  278. {
  279. this->disableCurrentSettings();
  280. }
  281. d->syncQStringPtrWithCharPtr();
  282. d->syncQStringListPtrWithStringVectorPtr();
  283. // Since CommandLineArguments include arg0 in the list
  284. // of remaining arguments, let's create a temporary list and remove it.
  285. QStringList _remaingingArguments = this->remainingArguments();
  286. _remaingingArguments.removeFirst();
  287. // Update ignored arguments list
  288. d->IgnoredArguments << _remaingingArguments;
  289. return res1 && res2;
  290. }
  291. //----------------------------------------------------------------------------
  292. QStringList ctkVTKCommandOptions::remainingArguments()
  293. {
  294. CTK_D(ctkVTKCommandOptions);
  295. QStringList tmp;
  296. for(int i=0; i < d->Argc; ++i)
  297. {
  298. tmp << d->Argv[i];
  299. }
  300. return tmp;
  301. }
  302. //----------------------------------------------------------------------------
  303. void ctkVTKCommandOptions::remainingArguments(int* argc, char*** argv)
  304. {
  305. CTK_D(ctkVTKCommandOptions);
  306. *argc = d->Argc;
  307. *argv = d->Argv;
  308. }
  309. //----------------------------------------------------------------------------
  310. void ctkVTKCommandOptions::addDeprecatedArgument(const char* longarg, const char* shortarg,
  311. const char* arghelp, int type)
  312. {
  313. CTK_D(ctkVTKCommandOptions);
  314. // If it is for settings or not for the current process do nothing
  315. if((type & ctkVTKCommandOptions::QSETTINGS_ONLY) ||
  316. !(type & d->ProcessType || type == ctkVTKCommandOptions::ALL))
  317. {
  318. return;
  319. }
  320. // Add a callback for the deprecated argument handling
  321. d->CMD.AddCallback(longarg, vtksys::CommandLineArguments::NO_ARGUMENT,
  322. ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler, this, arghelp);
  323. if(shortarg)
  324. {
  325. d->CMD.AddCallback(shortarg, vtksys::CommandLineArguments::NO_ARGUMENT,
  326. ctkVTKCommandOptionsPrivate::deprecatedArgumentHandler, this, arghelp);
  327. }
  328. }
  329. //----------------------------------------------------------------------------
  330. bool ctkVTKCommandOptions::deprecatedArgument(const char* argument)
  331. {
  332. CTK_D(ctkVTKCommandOptions);
  333. d->ErrorMessage = QString(" %1").arg(d->CMD.GetHelp(argument));
  334. return false;
  335. }
  336. //----------------------------------------------------------------------------
  337. bool ctkVTKCommandOptions::wrongArgument(const char* argument)
  338. {
  339. Q_UNUSED(argument);
  340. return false;
  341. }
  342. //----------------------------------------------------------------------------
  343. void ctkVTKCommandOptions::addBooleanArgument(const char* longarg, const char* shortarg,
  344. bool* var, const char* arghelp,
  345. bool defaultValue, int type)
  346. {
  347. CTK_D(ctkVTKCommandOptions);
  348. // Attempt to read from settings only if longarg is different from '--disable-settings'.
  349. if (QLatin1String(longarg) != "--disable-settings")
  350. {
  351. *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toBool();
  352. if(type & ctkVTKCommandOptions::QSETTINGS_ONLY)
  353. {
  354. return;
  355. }
  356. }
  357. // If the process type matches then add the argument to the command line
  358. if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL)
  359. {
  360. d->CMD.AddBooleanArgument(longarg, var, arghelp);
  361. if (shortarg)
  362. {
  363. d->CMD.AddBooleanArgument(shortarg, var, longarg);
  364. }
  365. }
  366. }
  367. //----------------------------------------------------------------------------
  368. void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg, QString* var,
  369. const char* arghelp, const QString& defaultValue, int type)
  370. {
  371. CTK_D(ctkVTKCommandOptions);
  372. *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toString();
  373. if(type & ctkVTKCommandOptions::QSETTINGS_ONLY)
  374. {
  375. return;
  376. }
  377. if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL)
  378. {
  379. char ** charstar = d->mapQStringPtrToCharPtr(var);
  380. typedef vtksys::CommandLineArguments argT;
  381. d->CMD.AddArgument(longarg, argT::EQUAL_ARGUMENT, charstar, arghelp);
  382. if ( shortarg )
  383. {
  384. d->CMD.AddArgument(shortarg, argT::EQUAL_ARGUMENT, charstar, longarg);
  385. }
  386. }
  387. }
  388. //----------------------------------------------------------------------------
  389. void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg,
  390. QStringList* var, const char* arghelp,
  391. const QStringList& defaultValue, int type)
  392. {
  393. CTK_D(ctkVTKCommandOptions);
  394. *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toStringList();
  395. if(type & ctkVTKCommandOptions::QSETTINGS_ONLY)
  396. {
  397. return;
  398. }
  399. if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL)
  400. {
  401. std::vector<std::string>* vectorPtr = d->mapQStringListPtrToStringVectorPtr(var);
  402. typedef vtksys::CommandLineArguments argT;
  403. d->CMD.AddArgument(longarg, argT::MULTI_ARGUMENT, vectorPtr, arghelp);
  404. if (shortarg)
  405. {
  406. d->CMD.AddArgument(shortarg, argT::MULTI_ARGUMENT, vectorPtr, longarg);
  407. }
  408. }
  409. }
  410. //----------------------------------------------------------------------------
  411. void ctkVTKCommandOptions::addArgument(const char* longarg, const char* shortarg, int* var,
  412. const char* arghelp, int defaultValue, int type)
  413. {
  414. CTK_D(ctkVTKCommandOptions);
  415. *var = d->Settings->value(QLatin1String(longarg+2), defaultValue).toInt();
  416. if(type & ctkVTKCommandOptions::QSETTINGS_ONLY)
  417. {
  418. return;
  419. }
  420. if(type & d->ProcessType || type == ctkVTKCommandOptions::ALL)
  421. {
  422. typedef vtksys::CommandLineArguments argT;
  423. d->CMD.AddArgument(longarg, argT::EQUAL_ARGUMENT, var, arghelp);
  424. if (shortarg)
  425. {
  426. d->CMD.AddArgument(shortarg, argT::EQUAL_ARGUMENT, var, longarg);
  427. }
  428. }
  429. }
  430. //----------------------------------------------------------------------------
  431. int ctkVTKCommandOptions::indexOfLastParsedArgument()
  432. {
  433. CTK_D(ctkVTKCommandOptions);
  434. return d->CMD.GetLastArgument();
  435. }