CommandLineArguments.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /*=========================================================================
  2. Program: KWSys - Kitware System Library
  3. Module: $RCSfile$
  4. Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
  5. See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  8. PURPOSE. See the above copyright notices for more information.
  9. =========================================================================*/
  10. #include "kwsysPrivate.h"
  11. #include KWSYS_HEADER(CommandLineArguments.hxx)
  12. #include KWSYS_HEADER(Configure.hxx)
  13. #include KWSYS_HEADER(stl/vector)
  14. #include KWSYS_HEADER(stl/map)
  15. #include KWSYS_HEADER(stl/set)
  16. #include KWSYS_HEADER(ios/sstream)
  17. #include KWSYS_HEADER(ios/iostream)
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #ifdef _MSC_VER
  21. # pragma warning (disable: 4786)
  22. #endif
  23. namespace KWSYS_NAMESPACE
  24. {
  25. //----------------------------------------------------------------------------
  26. //============================================================================
  27. class CommandLineArgumentsString : public kwsys_stl::string
  28. {
  29. public:
  30. typedef kwsys_stl::string StdString;
  31. CommandLineArgumentsString(): StdString() {}
  32. CommandLineArgumentsString(const value_type* s): StdString(s) {}
  33. CommandLineArgumentsString(const value_type* s, size_type n): StdString(s, n) {}
  34. CommandLineArgumentsString(const StdString& s, size_type pos=0, size_type n=npos):
  35. StdString(s, pos, n) {}
  36. };
  37. struct CommandLineArgumentsCallbackStructure
  38. {
  39. const char* Argument;
  40. int ArgumentType;
  41. CommandLineArguments::CallbackType Callback;
  42. void* CallData;
  43. void* Variable;
  44. int VariableType;
  45. const char* Help;
  46. };
  47. class CommandLineArgumentsVectorOfStrings :
  48. public kwsys_stl::vector<CommandLineArgumentsString> {};
  49. class CommandLineArgumentsSetOfStrings :
  50. public kwsys_stl::set<CommandLineArgumentsString> {};
  51. class CommandLineArgumentsMapOfStrucs :
  52. public kwsys_stl::map<CommandLineArgumentsString,
  53. CommandLineArgumentsCallbackStructure> {};
  54. class CommandLineArgumentsInternal
  55. {
  56. public:
  57. CommandLineArgumentsInternal()
  58. {
  59. this->UnknownArgumentCallback = 0;
  60. this->ClientData = 0;
  61. this->LastArgument = 0;
  62. }
  63. typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
  64. typedef CommandLineArgumentsMapOfStrucs CallbacksMap;
  65. typedef CommandLineArgumentsString String;
  66. typedef CommandLineArgumentsSetOfStrings SetOfStrings;
  67. VectorOfStrings Argv;
  68. CallbacksMap Callbacks;
  69. CommandLineArguments::ErrorCallbackType UnknownArgumentCallback;
  70. void* ClientData;
  71. VectorOfStrings::size_type LastArgument;
  72. };
  73. //============================================================================
  74. //----------------------------------------------------------------------------
  75. //----------------------------------------------------------------------------
  76. CommandLineArguments::CommandLineArguments()
  77. {
  78. this->Internals = new CommandLineArguments::Internal;
  79. this->Help = "";
  80. this->LineLength = 80;
  81. }
  82. //----------------------------------------------------------------------------
  83. CommandLineArguments::~CommandLineArguments()
  84. {
  85. delete this->Internals;
  86. }
  87. //----------------------------------------------------------------------------
  88. void CommandLineArguments::Initialize(int argc, const char* const argv[])
  89. {
  90. int cc;
  91. this->Initialize();
  92. for ( cc = 1; cc < argc; cc ++ )
  93. {
  94. this->ProcessArgument(argv[cc]);
  95. }
  96. }
  97. //----------------------------------------------------------------------------
  98. void CommandLineArguments::Initialize(int argc, char* argv[])
  99. {
  100. int cc;
  101. this->Initialize();
  102. for ( cc = 1; cc < argc; cc ++ )
  103. {
  104. this->ProcessArgument(argv[cc]);
  105. }
  106. }
  107. //----------------------------------------------------------------------------
  108. void CommandLineArguments::Initialize()
  109. {
  110. this->Internals->Argv.clear();
  111. this->Internals->LastArgument = 0;
  112. }
  113. //----------------------------------------------------------------------------
  114. void CommandLineArguments::ProcessArgument(const char* arg)
  115. {
  116. this->Internals->Argv.push_back(arg);
  117. }
  118. //----------------------------------------------------------------------------
  119. int CommandLineArguments::Parse()
  120. {
  121. CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  122. CommandLineArguments::Internal::VectorOfStrings matches;
  123. for ( cc = 0; cc < this->Internals->Argv.size(); cc ++ )
  124. {
  125. matches.clear();
  126. CommandLineArguments::Internal::String& arg = this->Internals->Argv[cc];
  127. CommandLineArguments::Internal::CallbacksMap::iterator it;
  128. // Does the argument match to any we know about?
  129. for ( it = this->Internals->Callbacks.begin();
  130. it != this->Internals->Callbacks.end();
  131. it ++ )
  132. {
  133. const CommandLineArguments::Internal::String& parg = it->first;
  134. CommandLineArgumentsCallbackStructure *cs = &it->second;
  135. if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT ||
  136. cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT)
  137. {
  138. if ( arg == parg )
  139. {
  140. matches.push_back(parg);
  141. }
  142. }
  143. else if ( arg.find( parg ) == 0 )
  144. {
  145. matches.push_back(parg);
  146. }
  147. }
  148. if ( matches.size() > 0 )
  149. {
  150. // Ok, we found one or more arguments that match what user specified.
  151. // Let's find the longest one.
  152. CommandLineArguments::Internal::VectorOfStrings::size_type kk;
  153. CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0;
  154. CommandLineArguments::Internal::String::size_type maxlen = 0;
  155. for ( kk = 0; kk < matches.size(); kk ++ )
  156. {
  157. if ( matches[kk].size() > maxlen )
  158. {
  159. maxlen = matches[kk].size();
  160. maxidx = kk;
  161. }
  162. }
  163. // So, the longest one is probably the right one. Now see if it has any
  164. // additional value
  165. const char* value = 0;
  166. CommandLineArgumentsCallbackStructure *cs
  167. = &this->Internals->Callbacks[matches[maxidx]];
  168. const CommandLineArguments::Internal::String& sarg = matches[maxidx];
  169. if ( cs->ArgumentType == NO_ARGUMENT )
  170. {
  171. // No value
  172. }
  173. else if ( cs->ArgumentType == SPACE_ARGUMENT )
  174. {
  175. if ( cc == this->Internals->Argv.size()-1 )
  176. {
  177. return 0;
  178. }
  179. // Value is the next argument
  180. value = this->Internals->Argv[cc+1].c_str();
  181. cc ++;
  182. }
  183. else if ( cs->ArgumentType == EQUAL_ARGUMENT )
  184. {
  185. if ( arg.size() == sarg.size() || *(arg.c_str() + sarg.size()) != '=' )
  186. {
  187. return 0;
  188. }
  189. // Value is everythng followed the '=' sign
  190. value = arg.c_str() + sarg.size()+1;
  191. }
  192. else if ( cs->ArgumentType == CONCAT_ARGUMENT )
  193. {
  194. // Value is whatever follows the argument
  195. value = arg.c_str() + sarg.size();
  196. }
  197. // Call the callback
  198. if ( cs->Callback )
  199. {
  200. if ( !cs->Callback(sarg.c_str(), value, cs->CallData) )
  201. {
  202. return 0;
  203. }
  204. }
  205. if ( cs->Variable )
  206. {
  207. kwsys_stl::string var = "1";
  208. if ( value )
  209. {
  210. var = value;
  211. }
  212. if ( cs->VariableType == CommandLineArguments::INT_TYPE )
  213. {
  214. int* variable = static_cast<int*>(cs->Variable);
  215. char* res = 0;
  216. *variable = strtol(var.c_str(), &res, 10);
  217. //if ( res && *res )
  218. // {
  219. // Can handle non-int
  220. // }
  221. }
  222. else if ( cs->VariableType == CommandLineArguments::DOUBLE_TYPE )
  223. {
  224. double* variable = static_cast<double*>(cs->Variable);
  225. char* res = 0;
  226. *variable = strtod(var.c_str(), &res);
  227. //if ( res && *res )
  228. // {
  229. // Can handle non-int
  230. // }
  231. }
  232. else if ( cs->VariableType == CommandLineArguments::STRING_TYPE )
  233. {
  234. char** variable = static_cast<char**>(cs->Variable);
  235. if ( *variable )
  236. {
  237. delete [] *variable;
  238. *variable = 0;
  239. }
  240. *variable = new char[ strlen(var.c_str()) + 1 ];
  241. strcpy(*variable, var.c_str());
  242. }
  243. else if ( cs->VariableType == CommandLineArguments::STL_STRING_TYPE )
  244. {
  245. kwsys_stl::string* variable = static_cast<kwsys_stl::string*>(cs->Variable);
  246. *variable = var;
  247. }
  248. else if ( cs->VariableType == CommandLineArguments::BOOL_TYPE )
  249. {
  250. bool* variable = static_cast<bool*>(cs->Variable);
  251. if ( var == "1" || var == "ON" || var == "TRUE" || var == "true" || var == "on" ||
  252. var == "True" || var == "yes" || var == "Yes" || var == "YES" )
  253. {
  254. *variable = true;
  255. }
  256. else
  257. {
  258. *variable = false;
  259. }
  260. }
  261. else
  262. {
  263. kwsys_ios::cerr << "Got unknown argument type: \"" << cs->VariableType << "\"" << kwsys_ios::endl;
  264. return 0;
  265. }
  266. }
  267. }
  268. else
  269. {
  270. // Handle unknown arguments
  271. if ( this->Internals->UnknownArgumentCallback )
  272. {
  273. if ( !this->Internals->UnknownArgumentCallback(arg.c_str(),
  274. this->Internals->ClientData) )
  275. {
  276. return 0;
  277. }
  278. return 1;
  279. }
  280. else
  281. {
  282. kwsys_ios::cerr << "Got unknown argument: \"" << arg.c_str() << "\"" << kwsys_ios::endl;
  283. return 0;
  284. }
  285. }
  286. }
  287. // We are done parsing, so remember what was the last argument
  288. this->Internals->LastArgument = cc;
  289. return 1;
  290. }
  291. //----------------------------------------------------------------------------
  292. void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv)
  293. {
  294. CommandLineArguments::Internal::VectorOfStrings::size_type size
  295. = this->Internals->Argv.size() - this->Internals->LastArgument + 1;
  296. CommandLineArguments::Internal::VectorOfStrings::size_type cc;
  297. char** args = new char*[ size ];
  298. args[0] = new char[ this->Internals->Argv[0].size() + 1 ];
  299. strcpy(args[0], this->Internals->Argv[0].c_str());
  300. int cnt = 1;
  301. for ( cc = this->Internals->LastArgument;
  302. cc < this->Internals->Argv.size(); cc ++ )
  303. {
  304. args[cnt] = new char[ this->Internals->Argv[cc].size() + 1];
  305. strcpy(args[cnt], this->Internals->Argv[cc].c_str());
  306. cnt ++;
  307. }
  308. *argc = cnt;
  309. *argv = args;
  310. }
  311. //----------------------------------------------------------------------------
  312. void CommandLineArguments::AddCallback(const char* argument, ArgumentTypeEnum type,
  313. CallbackType callback, void* call_data, const char* help)
  314. {
  315. CommandLineArgumentsCallbackStructure s;
  316. s.Argument = argument;
  317. s.ArgumentType = type;
  318. s.Callback = callback;
  319. s.CallData = call_data;
  320. s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE;
  321. s.Variable = 0;
  322. s.Help = help;
  323. this->Internals->Callbacks[argument] = s;
  324. this->GenerateHelp();
  325. }
  326. //----------------------------------------------------------------------------
  327. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  328. VariableTypeEnum vtype, void* variable, const char* help)
  329. {
  330. CommandLineArgumentsCallbackStructure s;
  331. s.Argument = argument;
  332. s.ArgumentType = type;
  333. s.Callback = 0;
  334. s.CallData = 0;
  335. s.VariableType = vtype;
  336. s.Variable = variable;
  337. s.Help = help;
  338. this->Internals->Callbacks[argument] = s;
  339. this->GenerateHelp();
  340. }
  341. //----------------------------------------------------------------------------
  342. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  343. int* variable, const char* help)
  344. {
  345. this->AddArgument(argument, type, CommandLineArguments::INT_TYPE, variable, help);
  346. }
  347. //----------------------------------------------------------------------------
  348. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  349. double* variable, const char* help)
  350. {
  351. this->AddArgument(argument, type, CommandLineArguments::DOUBLE_TYPE, variable, help);
  352. }
  353. //----------------------------------------------------------------------------
  354. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  355. char** variable, const char* help)
  356. {
  357. this->AddArgument(argument, type, CommandLineArguments::STRING_TYPE, variable, help);
  358. }
  359. //----------------------------------------------------------------------------
  360. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  361. kwsys_stl::string* variable, const char* help)
  362. {
  363. this->AddArgument(argument, type, CommandLineArguments::STL_STRING_TYPE, variable, help);
  364. }
  365. //----------------------------------------------------------------------------
  366. void CommandLineArguments::AddArgument(const char* argument, ArgumentTypeEnum type,
  367. bool* variable, const char* help)
  368. {
  369. this->AddArgument(argument, type, CommandLineArguments::BOOL_TYPE, variable, help);
  370. }
  371. //----------------------------------------------------------------------------
  372. void CommandLineArguments::AddBooleanArgument(const char* argument, bool*
  373. variable, const char* help)
  374. {
  375. this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
  376. CommandLineArguments::BOOL_TYPE, variable, help);
  377. }
  378. //----------------------------------------------------------------------------
  379. void CommandLineArguments::AddBooleanArgument(const char* argument, int*
  380. variable, const char* help)
  381. {
  382. this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT,
  383. CommandLineArguments::INT_TYPE, variable, help);
  384. }
  385. //----------------------------------------------------------------------------
  386. void CommandLineArguments::SetClientData(void* client_data)
  387. {
  388. this->Internals->ClientData = client_data;
  389. }
  390. //----------------------------------------------------------------------------
  391. void CommandLineArguments::SetUnknownArgumentCallback(
  392. CommandLineArguments::ErrorCallbackType callback)
  393. {
  394. this->Internals->UnknownArgumentCallback = callback;
  395. }
  396. //----------------------------------------------------------------------------
  397. const char* CommandLineArguments::GetHelp(const char* arg)
  398. {
  399. CommandLineArguments::Internal::CallbacksMap::iterator it
  400. = this->Internals->Callbacks.find(arg);
  401. if ( it == this->Internals->Callbacks.end() )
  402. {
  403. return 0;
  404. }
  405. // Since several arguments may point to the same argument, find the one this
  406. // one point to if this one is pointing to another argument.
  407. CommandLineArgumentsCallbackStructure *cs = &(it->second);
  408. while ( 1 )
  409. {
  410. CommandLineArguments::Internal::CallbacksMap::iterator hit
  411. = this->Internals->Callbacks.find(cs->Help);
  412. if ( hit == this->Internals->Callbacks.end() )
  413. {
  414. return cs->Help;
  415. }
  416. cs = &(hit->second);
  417. }
  418. // Should never happened
  419. return 0;
  420. }
  421. //----------------------------------------------------------------------------
  422. void CommandLineArguments::GenerateHelp()
  423. {
  424. kwsys_ios::ostringstream str;
  425. // Collapse all arguments into the map of vectors of all arguments that do
  426. // the same thing.
  427. CommandLineArguments::Internal::CallbacksMap::iterator it;
  428. typedef kwsys_stl::map<CommandLineArguments::Internal::String,
  429. CommandLineArguments::Internal::SetOfStrings > MapArgs;
  430. MapArgs mp;
  431. MapArgs::iterator mpit, smpit;
  432. for ( it = this->Internals->Callbacks.begin();
  433. it != this->Internals->Callbacks.end();
  434. it ++ )
  435. {
  436. CommandLineArgumentsCallbackStructure *cs = &(it->second);
  437. mpit = mp.find(cs->Help);
  438. if ( mpit != mp.end() )
  439. {
  440. mpit->second.insert(it->first);
  441. mp[it->first].insert(it->first);
  442. }
  443. else
  444. {
  445. mp[it->first].insert(it->first);
  446. }
  447. }
  448. for ( it = this->Internals->Callbacks.begin();
  449. it != this->Internals->Callbacks.end();
  450. it ++ )
  451. {
  452. CommandLineArgumentsCallbackStructure *cs = &(it->second);
  453. mpit = mp.find(cs->Help);
  454. if ( mpit != mp.end() )
  455. {
  456. mpit->second.insert(it->first);
  457. smpit = mp.find(it->first);
  458. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  459. for ( sit = smpit->second.begin(); sit != smpit->second.end(); sit++ )
  460. {
  461. mpit->second.insert(*sit);
  462. }
  463. mp.erase(smpit);
  464. }
  465. else
  466. {
  467. mp[it->first].insert(it->first);
  468. }
  469. }
  470. // Find the length of the longest string
  471. CommandLineArguments::Internal::String::size_type maxlen = 0;
  472. for ( mpit = mp.begin();
  473. mpit != mp.end();
  474. mpit ++ )
  475. {
  476. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  477. for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
  478. {
  479. CommandLineArguments::Internal::String::size_type clen = sit->size();
  480. switch ( this->Internals->Callbacks[*sit].ArgumentType )
  481. {
  482. case CommandLineArguments::NO_ARGUMENT: clen += 0; break;
  483. case CommandLineArguments::CONCAT_ARGUMENT: clen += 6; break;
  484. case CommandLineArguments::SPACE_ARGUMENT: clen += 7; break;
  485. case CommandLineArguments::EQUAL_ARGUMENT: clen += 7; break;
  486. }
  487. if ( clen > maxlen )
  488. {
  489. maxlen = clen;
  490. }
  491. }
  492. }
  493. // Create format for that string
  494. char format[80];
  495. sprintf(format, "%%%ds", static_cast<unsigned int>(maxlen));
  496. // Print help for each option
  497. for ( mpit = mp.begin();
  498. mpit != mp.end();
  499. mpit ++ )
  500. {
  501. CommandLineArguments::Internal::SetOfStrings::iterator sit;
  502. for ( sit = mpit->second.begin(); sit != mpit->second.end(); sit++ )
  503. {
  504. str << kwsys_ios::endl;
  505. char argument[100];
  506. sprintf(argument, sit->c_str());
  507. switch ( this->Internals->Callbacks[*sit].ArgumentType )
  508. {
  509. case CommandLineArguments::NO_ARGUMENT: break;
  510. case CommandLineArguments::CONCAT_ARGUMENT: strcat(argument, "option"); break;
  511. case CommandLineArguments::SPACE_ARGUMENT: strcat(argument, " option"); break;
  512. case CommandLineArguments::EQUAL_ARGUMENT: strcat(argument, "=option"); break;
  513. }
  514. char buffer[80];
  515. sprintf(buffer, format, argument);
  516. str << buffer;
  517. }
  518. str << "\t";
  519. const char* ptr = this->Internals->Callbacks[mpit->first].Help;
  520. int len = strlen(ptr);
  521. int cnt = 0;
  522. while ( len > 0)
  523. {
  524. // If argument with help is longer than line length, split it on previous
  525. // space (or tab) and continue on the next line
  526. CommandLineArguments::Internal::String::size_type cc;
  527. for ( cc = 0; ptr[cc]; cc ++ )
  528. {
  529. if ( *ptr == ' ' || *ptr == '\t' )
  530. {
  531. ptr ++;
  532. len --;
  533. }
  534. }
  535. if ( cnt > 0 )
  536. {
  537. for ( cc = 0; cc < maxlen; cc ++ )
  538. {
  539. str << " ";
  540. }
  541. str << "\t";
  542. }
  543. CommandLineArguments::Internal::String::size_type skip = len;
  544. if ( skip > this->LineLength - maxlen )
  545. {
  546. skip = this->LineLength - maxlen;
  547. for ( cc = skip-1; cc > 0; cc -- )
  548. {
  549. if ( ptr[cc] == ' ' || ptr[cc] == '\t' )
  550. {
  551. break;
  552. }
  553. }
  554. if ( cc != 0 )
  555. {
  556. skip = cc;
  557. }
  558. }
  559. str.write(ptr, skip);
  560. str << kwsys_ios::endl;
  561. ptr += skip;
  562. len -= skip;
  563. cnt ++;
  564. }
  565. }
  566. this->Help = str.str();
  567. }
  568. } // namespace KWSYS_NAMESPACE