cmStringCommand.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmStringCommand.h"
  11. #include "cmCryptoHash.h"
  12. #include <cmsys/RegularExpression.hxx>
  13. #include <cmsys/SystemTools.hxx>
  14. #include <stdlib.h> // required for atoi
  15. #include <ctype.h>
  16. #include <time.h>
  17. #include <cmTimestamp.h>
  18. #include <cmUuid.h>
  19. //----------------------------------------------------------------------------
  20. bool cmStringCommand
  21. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  22. {
  23. if(args.size() < 1)
  24. {
  25. this->SetError("must be called with at least one argument.");
  26. return false;
  27. }
  28. const std::string &subCommand = args[0];
  29. if(subCommand == "REGEX")
  30. {
  31. return this->HandleRegexCommand(args);
  32. }
  33. else if(subCommand == "REPLACE")
  34. {
  35. return this->HandleReplaceCommand(args);
  36. }
  37. else if ( subCommand == "MD5" ||
  38. subCommand == "SHA1" ||
  39. subCommand == "SHA224" ||
  40. subCommand == "SHA256" ||
  41. subCommand == "SHA384" ||
  42. subCommand == "SHA512" )
  43. {
  44. return this->HandleHashCommand(args);
  45. }
  46. else if(subCommand == "TOLOWER")
  47. {
  48. return this->HandleToUpperLowerCommand(args, false);
  49. }
  50. else if(subCommand == "TOUPPER")
  51. {
  52. return this->HandleToUpperLowerCommand(args, true);
  53. }
  54. else if(subCommand == "COMPARE")
  55. {
  56. return this->HandleCompareCommand(args);
  57. }
  58. else if(subCommand == "ASCII")
  59. {
  60. return this->HandleAsciiCommand(args);
  61. }
  62. else if(subCommand == "CONFIGURE")
  63. {
  64. return this->HandleConfigureCommand(args);
  65. }
  66. else if(subCommand == "LENGTH")
  67. {
  68. return this->HandleLengthCommand(args);
  69. }
  70. else if(subCommand == "CONCAT")
  71. {
  72. return this->HandleConcatCommand(args);
  73. }
  74. else if(subCommand == "SUBSTRING")
  75. {
  76. return this->HandleSubstringCommand(args);
  77. }
  78. else if(subCommand == "STRIP")
  79. {
  80. return this->HandleStripCommand(args);
  81. }
  82. else if(subCommand == "RANDOM")
  83. {
  84. return this->HandleRandomCommand(args);
  85. }
  86. else if(subCommand == "FIND")
  87. {
  88. return this->HandleFindCommand(args);
  89. }
  90. else if(subCommand == "TIMESTAMP")
  91. {
  92. return this->HandleTimestampCommand(args);
  93. }
  94. else if(subCommand == "MAKE_C_IDENTIFIER")
  95. {
  96. return this->HandleMakeCIdentifierCommand(args);
  97. }
  98. else if(subCommand == "GENEX_STRIP")
  99. {
  100. return this->HandleGenexStripCommand(args);
  101. }
  102. else if(subCommand == "UUID")
  103. {
  104. return this->HandleUuidCommand(args);
  105. }
  106. std::string e = "does not recognize sub-command "+subCommand;
  107. this->SetError(e);
  108. return false;
  109. }
  110. //----------------------------------------------------------------------------
  111. bool cmStringCommand::HandleHashCommand(std::vector<std::string> const& args)
  112. {
  113. #if defined(CMAKE_BUILD_WITH_CMAKE)
  114. if(args.size() != 3)
  115. {
  116. std::ostringstream e;
  117. e << args[0] << " requires an output variable and an input string";
  118. this->SetError(e.str());
  119. return false;
  120. }
  121. cmsys::auto_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
  122. if(hash.get())
  123. {
  124. std::string out = hash->HashString(args[2]);
  125. this->Makefile->AddDefinition(args[1], out.c_str());
  126. return true;
  127. }
  128. return false;
  129. #else
  130. std::ostringstream e;
  131. e << args[0] << " not available during bootstrap";
  132. this->SetError(e.str().c_str());
  133. return false;
  134. #endif
  135. }
  136. //----------------------------------------------------------------------------
  137. bool cmStringCommand::HandleToUpperLowerCommand(
  138. std::vector<std::string> const& args, bool toUpper)
  139. {
  140. if ( args.size() < 3 )
  141. {
  142. this->SetError("no output variable specified");
  143. return false;
  144. }
  145. std::string outvar = args[2];
  146. std::string output;
  147. if (toUpper)
  148. {
  149. output = cmSystemTools::UpperCase(args[1]);
  150. }
  151. else
  152. {
  153. output = cmSystemTools::LowerCase(args[1]);
  154. }
  155. // Store the output in the provided variable.
  156. this->Makefile->AddDefinition(outvar, output.c_str());
  157. return true;
  158. }
  159. //----------------------------------------------------------------------------
  160. bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args)
  161. {
  162. if ( args.size() < 3 )
  163. {
  164. this->SetError("No output variable specified");
  165. return false;
  166. }
  167. std::string::size_type cc;
  168. std::string outvar = args[args.size()-1];
  169. std::string output = "";
  170. for ( cc = 1; cc < args.size()-1; cc ++ )
  171. {
  172. int ch = atoi(args[cc].c_str());
  173. if ( ch > 0 && ch < 256 )
  174. {
  175. output += static_cast<char>(ch);
  176. }
  177. else
  178. {
  179. std::string error = "Character with code ";
  180. error += args[cc];
  181. error += " does not exist.";
  182. this->SetError(error);
  183. return false;
  184. }
  185. }
  186. // Store the output in the provided variable.
  187. this->Makefile->AddDefinition(outvar, output.c_str());
  188. return true;
  189. }
  190. //----------------------------------------------------------------------------
  191. bool cmStringCommand::HandleConfigureCommand(
  192. std::vector<std::string> const& args)
  193. {
  194. if ( args.size() < 2 )
  195. {
  196. this->SetError("No input string specified.");
  197. return false;
  198. }
  199. else if ( args.size() < 3 )
  200. {
  201. this->SetError("No output variable specified.");
  202. return false;
  203. }
  204. // Parse options.
  205. bool escapeQuotes = false;
  206. bool atOnly = false;
  207. for(unsigned int i = 3; i < args.size(); ++i)
  208. {
  209. if(args[i] == "@ONLY")
  210. {
  211. atOnly = true;
  212. }
  213. else if(args[i] == "ESCAPE_QUOTES")
  214. {
  215. escapeQuotes = true;
  216. }
  217. else
  218. {
  219. std::ostringstream err;
  220. err << "Unrecognized argument \"" << args[i] << "\"";
  221. this->SetError(err.str());
  222. return false;
  223. }
  224. }
  225. // Configure the string.
  226. std::string output;
  227. this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
  228. // Store the output in the provided variable.
  229. this->Makefile->AddDefinition(args[2], output.c_str());
  230. return true;
  231. }
  232. //----------------------------------------------------------------------------
  233. bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args)
  234. {
  235. if(args.size() < 2)
  236. {
  237. this->SetError("sub-command REGEX requires a mode to be specified.");
  238. return false;
  239. }
  240. std::string mode = args[1];
  241. if(mode == "MATCH")
  242. {
  243. if(args.size() < 5)
  244. {
  245. this->SetError("sub-command REGEX, mode MATCH needs "
  246. "at least 5 arguments total to command.");
  247. return false;
  248. }
  249. return this->RegexMatch(args);
  250. }
  251. else if(mode == "MATCHALL")
  252. {
  253. if(args.size() < 5)
  254. {
  255. this->SetError("sub-command REGEX, mode MATCHALL needs "
  256. "at least 5 arguments total to command.");
  257. return false;
  258. }
  259. return this->RegexMatchAll(args);
  260. }
  261. else if(mode == "REPLACE")
  262. {
  263. if(args.size() < 6)
  264. {
  265. this->SetError("sub-command REGEX, mode REPLACE needs "
  266. "at least 6 arguments total to command.");
  267. return false;
  268. }
  269. return this->RegexReplace(args);
  270. }
  271. std::string e = "sub-command REGEX does not recognize mode "+mode;
  272. this->SetError(e);
  273. return false;
  274. }
  275. //----------------------------------------------------------------------------
  276. bool cmStringCommand::RegexMatch(std::vector<std::string> const& args)
  277. {
  278. //"STRING(REGEX MATCH <regular_expression> <output variable>
  279. // <input> [<input>...])\n";
  280. std::string regex = args[2];
  281. std::string outvar = args[3];
  282. this->Makefile->ClearMatches();
  283. // Compile the regular expression.
  284. cmsys::RegularExpression re;
  285. if(!re.compile(regex.c_str()))
  286. {
  287. std::string e =
  288. "sub-command REGEX, mode MATCH failed to compile regex \""+regex+"\".";
  289. this->SetError(e);
  290. return false;
  291. }
  292. // Concatenate all the last arguments together.
  293. std::string input = cmJoin(cmRange(args).advance(4), std::string());
  294. // Scan through the input for all matches.
  295. std::string output;
  296. if(re.find(input.c_str()))
  297. {
  298. this->Makefile->StoreMatches(re);
  299. std::string::size_type l = re.start();
  300. std::string::size_type r = re.end();
  301. if(r-l == 0)
  302. {
  303. std::string e =
  304. "sub-command REGEX, mode MATCH regex \""+regex+
  305. "\" matched an empty string.";
  306. this->SetError(e);
  307. return false;
  308. }
  309. output = input.substr(l, r-l);
  310. }
  311. // Store the output in the provided variable.
  312. this->Makefile->AddDefinition(outvar, output.c_str());
  313. return true;
  314. }
  315. //----------------------------------------------------------------------------
  316. bool cmStringCommand::RegexMatchAll(std::vector<std::string> const& args)
  317. {
  318. //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
  319. // [<input>...])\n";
  320. std::string regex = args[2];
  321. std::string outvar = args[3];
  322. this->Makefile->ClearMatches();
  323. // Compile the regular expression.
  324. cmsys::RegularExpression re;
  325. if(!re.compile(regex.c_str()))
  326. {
  327. std::string e =
  328. "sub-command REGEX, mode MATCHALL failed to compile regex \""+
  329. regex+"\".";
  330. this->SetError(e);
  331. return false;
  332. }
  333. // Concatenate all the last arguments together.
  334. std::string input = cmJoin(cmRange(args).advance(4), std::string());
  335. // Scan through the input for all matches.
  336. std::string output;
  337. const char* p = input.c_str();
  338. while(re.find(p))
  339. {
  340. this->Makefile->StoreMatches(re);
  341. std::string::size_type l = re.start();
  342. std::string::size_type r = re.end();
  343. if(r-l == 0)
  344. {
  345. std::string e = "sub-command REGEX, mode MATCHALL regex \""+
  346. regex+"\" matched an empty string.";
  347. this->SetError(e);
  348. return false;
  349. }
  350. if(!output.empty())
  351. {
  352. output += ";";
  353. }
  354. output += std::string(p+l, r-l);
  355. p += r;
  356. }
  357. // Store the output in the provided variable.
  358. this->Makefile->AddDefinition(outvar, output.c_str());
  359. return true;
  360. }
  361. //----------------------------------------------------------------------------
  362. bool cmStringCommand::RegexReplace(std::vector<std::string> const& args)
  363. {
  364. //"STRING(REGEX REPLACE <regular_expression> <replace_expression>
  365. // <output variable> <input> [<input>...])\n"
  366. std::string regex = args[2];
  367. std::string replace = args[3];
  368. std::string outvar = args[4];
  369. // Pull apart the replace expression to find the escaped [0-9] values.
  370. std::vector<RegexReplacement> replacement;
  371. std::string::size_type l = 0;
  372. while(l < replace.length())
  373. {
  374. std::string::size_type r = replace.find("\\", l);
  375. if(r == std::string::npos)
  376. {
  377. r = replace.length();
  378. replacement.push_back(replace.substr(l, r-l));
  379. }
  380. else
  381. {
  382. if(r-l > 0)
  383. {
  384. replacement.push_back(replace.substr(l, r-l));
  385. }
  386. if(r == (replace.length()-1))
  387. {
  388. this->SetError("sub-command REGEX, mode REPLACE: "
  389. "replace-expression ends in a backslash.");
  390. return false;
  391. }
  392. if((replace[r+1] >= '0') && (replace[r+1] <= '9'))
  393. {
  394. replacement.push_back(replace[r+1]-'0');
  395. }
  396. else if(replace[r+1] == 'n')
  397. {
  398. replacement.push_back("\n");
  399. }
  400. else if(replace[r+1] == '\\')
  401. {
  402. replacement.push_back("\\");
  403. }
  404. else
  405. {
  406. std::string e = "sub-command REGEX, mode REPLACE: Unknown escape \"";
  407. e += replace.substr(r, 2);
  408. e += "\" in replace-expression.";
  409. this->SetError(e);
  410. return false;
  411. }
  412. r += 2;
  413. }
  414. l = r;
  415. }
  416. this->Makefile->ClearMatches();
  417. // Compile the regular expression.
  418. cmsys::RegularExpression re;
  419. if(!re.compile(regex.c_str()))
  420. {
  421. std::string e =
  422. "sub-command REGEX, mode REPLACE failed to compile regex \""+
  423. regex+"\".";
  424. this->SetError(e);
  425. return false;
  426. }
  427. // Concatenate all the last arguments together.
  428. std::string input = cmJoin(cmRange(args).advance(5), std::string());
  429. // Scan through the input for all matches.
  430. std::string output;
  431. std::string::size_type base = 0;
  432. while(re.find(input.c_str()+base))
  433. {
  434. this->Makefile->StoreMatches(re);
  435. std::string::size_type l2 = re.start();
  436. std::string::size_type r = re.end();
  437. // Concatenate the part of the input that was not matched.
  438. output += input.substr(base, l2);
  439. // Make sure the match had some text.
  440. if(r-l2 == 0)
  441. {
  442. std::string e = "sub-command REGEX, mode REPLACE regex \""+
  443. regex+"\" matched an empty string.";
  444. this->SetError(e);
  445. return false;
  446. }
  447. // Concatenate the replacement for the match.
  448. for(unsigned int i=0; i < replacement.size(); ++i)
  449. {
  450. if(replacement[i].number < 0)
  451. {
  452. // This is just a plain-text part of the replacement.
  453. output += replacement[i].value;
  454. }
  455. else
  456. {
  457. // Replace with part of the match.
  458. int n = replacement[i].number;
  459. std::string::size_type start = re.start(n);
  460. std::string::size_type end = re.end(n);
  461. std::string::size_type len = input.length()-base;
  462. if((start != std::string::npos) && (end != std::string::npos) &&
  463. (start <= len) && (end <= len))
  464. {
  465. output += input.substr(base+start, end-start);
  466. }
  467. else
  468. {
  469. std::string e =
  470. "sub-command REGEX, mode REPLACE: replace expression \""+
  471. replace+"\" contains an out-of-range escape for regex \""+
  472. regex+"\".";
  473. this->SetError(e);
  474. return false;
  475. }
  476. }
  477. }
  478. // Move past the match.
  479. base += r;
  480. }
  481. // Concatenate the text after the last match.
  482. output += input.substr(base, input.length()-base);
  483. // Store the output in the provided variable.
  484. this->Makefile->AddDefinition(outvar, output.c_str());
  485. return true;
  486. }
  487. //----------------------------------------------------------------------------
  488. bool cmStringCommand::HandleFindCommand(std::vector<std::string> const&
  489. args)
  490. {
  491. // check if all required parameters were passed
  492. if(args.size() < 4 || args.size() > 5)
  493. {
  494. this->SetError("sub-command FIND requires 3 or 4 parameters.");
  495. return false;
  496. }
  497. // check if the reverse flag was set or not
  498. bool reverseMode = false;
  499. if(args.size() == 5 && args[4] == "REVERSE")
  500. {
  501. reverseMode = true;
  502. }
  503. // if we have 5 arguments the last one must be REVERSE
  504. if(args.size() == 5 && args[4] != "REVERSE")
  505. {
  506. this->SetError("sub-command FIND: unknown last parameter");
  507. return false;
  508. }
  509. // local parameter names.
  510. const std::string& sstring = args[1];
  511. const std::string& schar = args[2];
  512. const std::string& outvar = args[3];
  513. // ensure that the user cannot accidentally specify REVERSE as a variable
  514. if(outvar == "REVERSE")
  515. {
  516. this->SetError("sub-command FIND does not allow to select REVERSE as "
  517. "the output variable. "
  518. "Maybe you missed the actual output variable?");
  519. return false;
  520. }
  521. // try to find the character and return its position
  522. size_t pos;
  523. if(!reverseMode)
  524. {
  525. pos = sstring.find(schar);
  526. }
  527. else
  528. {
  529. pos = sstring.rfind(schar);
  530. }
  531. if(std::string::npos != pos)
  532. {
  533. std::ostringstream s;
  534. s << pos;
  535. this->Makefile->AddDefinition(outvar, s.str().c_str());
  536. return true;
  537. }
  538. // the character was not found, but this is not really an error
  539. this->Makefile->AddDefinition(outvar, "-1");
  540. return true;
  541. }
  542. //----------------------------------------------------------------------------
  543. bool cmStringCommand::HandleCompareCommand(std::vector<std::string> const&
  544. args)
  545. {
  546. if(args.size() < 2)
  547. {
  548. this->SetError("sub-command COMPARE requires a mode to be specified.");
  549. return false;
  550. }
  551. std::string mode = args[1];
  552. if((mode == "EQUAL") || (mode == "NOTEQUAL") ||
  553. (mode == "LESS") || (mode == "GREATER"))
  554. {
  555. if(args.size() < 5)
  556. {
  557. std::string e = "sub-command COMPARE, mode ";
  558. e += mode;
  559. e += " needs at least 5 arguments total to command.";
  560. this->SetError(e);
  561. return false;
  562. }
  563. const std::string& left = args[2];
  564. const std::string& right = args[3];
  565. const std::string& outvar = args[4];
  566. bool result;
  567. if(mode == "LESS")
  568. {
  569. result = (left < right);
  570. }
  571. else if(mode == "GREATER")
  572. {
  573. result = (left > right);
  574. }
  575. else if(mode == "EQUAL")
  576. {
  577. result = (left == right);
  578. }
  579. else // if(mode == "NOTEQUAL")
  580. {
  581. result = !(left == right);
  582. }
  583. if(result)
  584. {
  585. this->Makefile->AddDefinition(outvar, "1");
  586. }
  587. else
  588. {
  589. this->Makefile->AddDefinition(outvar, "0");
  590. }
  591. return true;
  592. }
  593. std::string e = "sub-command COMPARE does not recognize mode "+mode;
  594. this->SetError(e);
  595. return false;
  596. }
  597. //----------------------------------------------------------------------------
  598. bool cmStringCommand::HandleReplaceCommand(std::vector<std::string> const&
  599. args)
  600. {
  601. if(args.size() < 5)
  602. {
  603. this->SetError("sub-command REPLACE requires at least four arguments.");
  604. return false;
  605. }
  606. const std::string& matchExpression = args[1];
  607. const std::string& replaceExpression = args[2];
  608. const std::string& variableName = args[3];
  609. std::string input = cmJoin(cmRange(args).advance(4), std::string());
  610. cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
  611. replaceExpression.c_str());
  612. this->Makefile->AddDefinition(variableName, input.c_str());
  613. return true;
  614. }
  615. //----------------------------------------------------------------------------
  616. bool cmStringCommand::HandleSubstringCommand(std::vector<std::string> const&
  617. args)
  618. {
  619. if(args.size() != 5)
  620. {
  621. this->SetError("sub-command SUBSTRING requires four arguments.");
  622. return false;
  623. }
  624. const std::string& stringValue = args[1];
  625. int begin = atoi(args[2].c_str());
  626. int end = atoi(args[3].c_str());
  627. const std::string& variableName = args[4];
  628. size_t stringLength = stringValue.size();
  629. int intStringLength = static_cast<int>(stringLength);
  630. if ( begin < 0 || begin > intStringLength )
  631. {
  632. std::ostringstream ostr;
  633. ostr << "begin index: " << begin << " is out of range 0 - "
  634. << stringLength;
  635. this->SetError(ostr.str());
  636. return false;
  637. }
  638. if ( end < -1 )
  639. {
  640. std::ostringstream ostr;
  641. ostr << "end index: " << end << " should be -1 or greater";
  642. this->SetError(ostr.str());
  643. return false;
  644. }
  645. this->Makefile->AddDefinition(variableName,
  646. stringValue.substr(begin, end).c_str());
  647. return true;
  648. }
  649. //----------------------------------------------------------------------------
  650. bool cmStringCommand
  651. ::HandleLengthCommand(std::vector<std::string> const& args)
  652. {
  653. if(args.size() != 3)
  654. {
  655. this->SetError("sub-command LENGTH requires two arguments.");
  656. return false;
  657. }
  658. const std::string& stringValue = args[1];
  659. const std::string& variableName = args[2];
  660. size_t length = stringValue.size();
  661. char buffer[1024];
  662. sprintf(buffer, "%d", static_cast<int>(length));
  663. this->Makefile->AddDefinition(variableName, buffer);
  664. return true;
  665. }
  666. //----------------------------------------------------------------------------
  667. bool cmStringCommand
  668. ::HandleConcatCommand(std::vector<std::string> const& args)
  669. {
  670. if(args.size() < 2)
  671. {
  672. this->SetError("sub-command CONCAT requires at least one argument.");
  673. return false;
  674. }
  675. std::string const& variableName = args[1];
  676. std::string value = cmJoin(cmRange(args).advance(2), std::string());
  677. this->Makefile->AddDefinition(variableName, value.c_str());
  678. return true;
  679. }
  680. //----------------------------------------------------------------------------
  681. bool cmStringCommand
  682. ::HandleMakeCIdentifierCommand(std::vector<std::string> const& args)
  683. {
  684. if(args.size() != 3)
  685. {
  686. this->SetError("sub-command MAKE_C_IDENTIFIER requires two arguments.");
  687. return false;
  688. }
  689. const std::string& input = args[1];
  690. const std::string& variableName = args[2];
  691. this->Makefile->AddDefinition(variableName,
  692. cmSystemTools::MakeCidentifier(input).c_str());
  693. return true;
  694. }
  695. //----------------------------------------------------------------------------
  696. bool cmStringCommand
  697. ::HandleGenexStripCommand(std::vector<std::string> const& args)
  698. {
  699. if(args.size() != 3)
  700. {
  701. this->SetError("sub-command GENEX_STRIP requires two arguments.");
  702. return false;
  703. }
  704. const std::string& input = args[1];
  705. std::string result = cmGeneratorExpression::Preprocess(input,
  706. cmGeneratorExpression::StripAllGeneratorExpressions);
  707. const std::string& variableName = args[2];
  708. this->Makefile->AddDefinition(variableName, result.c_str());
  709. return true;
  710. }
  711. //----------------------------------------------------------------------------
  712. bool cmStringCommand::HandleStripCommand(
  713. std::vector<std::string> const& args)
  714. {
  715. if(args.size() != 3)
  716. {
  717. this->SetError("sub-command STRIP requires two arguments.");
  718. return false;
  719. }
  720. const std::string& stringValue = args[1];
  721. const std::string& variableName = args[2];
  722. size_t inStringLength = stringValue.size();
  723. size_t startPos = inStringLength + 1;
  724. size_t endPos = 0;
  725. const char* ptr = stringValue.c_str();
  726. size_t cc;
  727. for ( cc = 0; cc < inStringLength; ++ cc )
  728. {
  729. if ( !isspace(*ptr) )
  730. {
  731. if ( startPos > inStringLength )
  732. {
  733. startPos = cc;
  734. }
  735. endPos = cc;
  736. }
  737. ++ ptr;
  738. }
  739. size_t outLength = 0;
  740. // if the input string didn't contain any non-space characters, return
  741. // an empty string
  742. if (startPos > inStringLength)
  743. {
  744. outLength = 0;
  745. startPos = 0;
  746. }
  747. else
  748. {
  749. outLength=endPos - startPos + 1;
  750. }
  751. this->Makefile->AddDefinition(variableName,
  752. stringValue.substr(startPos, outLength).c_str());
  753. return true;
  754. }
  755. //----------------------------------------------------------------------------
  756. bool cmStringCommand
  757. ::HandleRandomCommand(std::vector<std::string> const& args)
  758. {
  759. if(args.size() < 2 || args.size() == 3 || args.size() == 5)
  760. {
  761. this->SetError("sub-command RANDOM requires at least one argument.");
  762. return false;
  763. }
  764. static bool seeded = false;
  765. bool force_seed = false;
  766. unsigned int seed = 0;
  767. int length = 5;
  768. const char cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
  769. "QWERTYUIOPASDFGHJKLZXCVBNM"
  770. "0123456789";
  771. std::string alphabet;
  772. if ( args.size() > 3 )
  773. {
  774. size_t i = 1;
  775. size_t stopAt = args.size() - 2;
  776. for ( ; i < stopAt; ++i )
  777. {
  778. if ( args[i] == "LENGTH" )
  779. {
  780. ++i;
  781. length = atoi(args[i].c_str());
  782. }
  783. else if ( args[i] == "ALPHABET" )
  784. {
  785. ++i;
  786. alphabet = args[i];
  787. }
  788. else if ( args[i] == "RANDOM_SEED" )
  789. {
  790. ++i;
  791. seed = static_cast<unsigned int>(atoi(args[i].c_str()));
  792. force_seed = true;
  793. }
  794. }
  795. }
  796. if (alphabet.empty())
  797. {
  798. alphabet = cmStringCommandDefaultAlphabet;
  799. }
  800. double sizeofAlphabet = static_cast<double>(alphabet.size());
  801. if ( sizeofAlphabet < 1 )
  802. {
  803. this->SetError("sub-command RANDOM invoked with bad alphabet.");
  804. return false;
  805. }
  806. if ( length < 1 )
  807. {
  808. this->SetError("sub-command RANDOM invoked with bad length.");
  809. return false;
  810. }
  811. const std::string& variableName = args[args.size()-1];
  812. std::vector<char> result;
  813. if (!seeded || force_seed)
  814. {
  815. seeded = true;
  816. srand(force_seed? seed : cmSystemTools::RandomSeed());
  817. }
  818. const char* alphaPtr = alphabet.c_str();
  819. int cc;
  820. for ( cc = 0; cc < length; cc ++ )
  821. {
  822. int idx=(int) (sizeofAlphabet* rand()/(RAND_MAX+1.0));
  823. result.push_back(*(alphaPtr + idx));
  824. }
  825. result.push_back(0);
  826. this->Makefile->AddDefinition(variableName, &*result.begin());
  827. return true;
  828. }
  829. //----------------------------------------------------------------------------
  830. bool cmStringCommand
  831. ::HandleTimestampCommand(std::vector<std::string> const& args)
  832. {
  833. if(args.size() < 2)
  834. {
  835. this->SetError("sub-command TIMESTAMP requires at least one argument.");
  836. return false;
  837. }
  838. else if(args.size() > 4)
  839. {
  840. this->SetError("sub-command TIMESTAMP takes at most three arguments.");
  841. return false;
  842. }
  843. unsigned int argsIndex = 1;
  844. const std::string &outputVariable = args[argsIndex++];
  845. std::string formatString;
  846. if(args.size() > argsIndex && args[argsIndex] != "UTC")
  847. {
  848. formatString = args[argsIndex++];
  849. }
  850. bool utcFlag = false;
  851. if(args.size() > argsIndex)
  852. {
  853. if(args[argsIndex] == "UTC")
  854. {
  855. utcFlag = true;
  856. }
  857. else
  858. {
  859. std::string e = " TIMESTAMP sub-command does not recognize option " +
  860. args[argsIndex] + ".";
  861. this->SetError(e);
  862. return false;
  863. }
  864. }
  865. cmTimestamp timestamp;
  866. std::string result = timestamp.CurrentTime(formatString, utcFlag);
  867. this->Makefile->AddDefinition(outputVariable, result.c_str());
  868. return true;
  869. }
  870. bool cmStringCommand
  871. ::HandleUuidCommand(std::vector<std::string> const& args)
  872. {
  873. #if defined(CMAKE_BUILD_WITH_CMAKE)
  874. unsigned int argsIndex = 1;
  875. if(args.size() < 2)
  876. {
  877. this->SetError("UUID sub-command requires an output variable.");
  878. return false;
  879. }
  880. const std::string &outputVariable = args[argsIndex++];
  881. std::string uuidNamespaceString;
  882. std::string uuidName;
  883. std::string uuidType;
  884. bool uuidUpperCase = false;
  885. while(args.size() > argsIndex)
  886. {
  887. if(args[argsIndex] == "NAMESPACE")
  888. {
  889. ++argsIndex;
  890. if(argsIndex >= args.size())
  891. {
  892. this->SetError("UUID sub-command, NAMESPACE requires a value.");
  893. return false;
  894. }
  895. uuidNamespaceString = args[argsIndex++];
  896. }
  897. else if(args[argsIndex] == "NAME")
  898. {
  899. ++argsIndex;
  900. if(argsIndex >= args.size())
  901. {
  902. this->SetError("UUID sub-command, NAME requires a value.");
  903. return false;
  904. }
  905. uuidName = args[argsIndex++];
  906. }
  907. else if(args[argsIndex] == "TYPE")
  908. {
  909. ++argsIndex;
  910. if(argsIndex >= args.size())
  911. {
  912. this->SetError("UUID sub-command, TYPE requires a value.");
  913. return false;
  914. }
  915. uuidType = args[argsIndex++];
  916. }
  917. else if(args[argsIndex] == "UPPER")
  918. {
  919. ++argsIndex;
  920. uuidUpperCase = true;
  921. }
  922. else
  923. {
  924. std::string e = "UUID sub-command does not recognize option " +
  925. args[argsIndex] + ".";
  926. this->SetError(e);
  927. return false;
  928. }
  929. }
  930. std::string uuid;
  931. cmUuid uuidGenerator;
  932. std::vector<unsigned char> uuidNamespace;
  933. if(!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace))
  934. {
  935. this->SetError("UUID sub-command, malformed NAMESPACE UUID.");
  936. return false;
  937. }
  938. if(uuidType == "MD5")
  939. {
  940. uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
  941. }
  942. else if(uuidType == "SHA1")
  943. {
  944. uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
  945. }
  946. else
  947. {
  948. std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
  949. this->SetError(e);
  950. return false;
  951. }
  952. if(uuid.empty())
  953. {
  954. this->SetError("UUID sub-command, generation failed.");
  955. return false;
  956. }
  957. if(uuidUpperCase)
  958. {
  959. uuid = cmSystemTools::UpperCase(uuid);
  960. }
  961. this->Makefile->AddDefinition(outputVariable, uuid.c_str());
  962. return true;
  963. #else
  964. std::ostringstream e;
  965. e << args[0] << " not available during bootstrap";
  966. this->SetError(e.str().c_str());
  967. return false;
  968. #endif
  969. }