cmStringCommand.cxx 26 KB

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