cmIfCommand.cxx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmIfCommand.h"
  14. #include "cmStringCommand.h"
  15. #include <stdlib.h> // required for atof
  16. #include <list>
  17. #include <cmsys/RegularExpression.hxx>
  18. //=========================================================================
  19. bool cmIfFunctionBlocker::
  20. IsFunctionBlocked(const cmListFileFunction& lff,
  21. cmMakefile &mf,
  22. cmExecutionStatus &inStatus)
  23. {
  24. // Prevent recusion and don't let this blocker block its own
  25. // commands.
  26. if (this->Executing)
  27. {
  28. return false;
  29. }
  30. // we start by recording all the functions
  31. if (!cmSystemTools::Strucmp(lff.Name.c_str(),"if"))
  32. {
  33. this->ScopeDepth++;
  34. }
  35. if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
  36. {
  37. this->ScopeDepth--;
  38. // if this is the endif for this if statement, then start executing
  39. if (!this->ScopeDepth)
  40. {
  41. // execute the functions for the true parts of the if statement
  42. this->Executing = true;
  43. cmExecutionStatus status;
  44. int scopeDepth = 0;
  45. for(unsigned int c = 0; c < this->Functions.size(); ++c)
  46. {
  47. // keep track of scope depth
  48. if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"if"))
  49. {
  50. scopeDepth++;
  51. }
  52. if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"endif"))
  53. {
  54. scopeDepth--;
  55. }
  56. // watch for our state change
  57. if (scopeDepth == 0 &&
  58. !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),"else"))
  59. {
  60. this->IsBlocking = this->HasRun;
  61. this->HasRun = true;
  62. }
  63. else if (scopeDepth == 0 && !cmSystemTools::Strucmp
  64. (this->Functions[c].Name.c_str(),"elseif"))
  65. {
  66. if (this->HasRun)
  67. {
  68. this->IsBlocking = true;
  69. }
  70. else
  71. {
  72. std::string errorString;
  73. std::vector<std::string> expandedArguments;
  74. mf.ExpandArguments(this->Functions[c].Arguments,
  75. expandedArguments);
  76. bool isTrue =
  77. cmIfCommand::IsTrue(expandedArguments,errorString,&mf);
  78. if (errorString.size())
  79. {
  80. std::string err = "had incorrect arguments: ";
  81. unsigned int i;
  82. for(i =0; i < this->Functions[c].Arguments.size(); ++i)
  83. {
  84. err += (this->Functions[c].Arguments[i].Quoted?"\"":"");
  85. err += this->Functions[c].Arguments[i].Value;
  86. err += (this->Functions[c].Arguments[i].Quoted?"\"":"");
  87. err += " ";
  88. }
  89. err += "(";
  90. err += errorString;
  91. err += ").";
  92. cmSystemTools::Error(err.c_str());
  93. return false;
  94. }
  95. if (isTrue)
  96. {
  97. this->IsBlocking = false;
  98. this->HasRun = true;
  99. }
  100. }
  101. }
  102. // should we execute?
  103. else if (!this->IsBlocking)
  104. {
  105. status.Clear();
  106. mf.ExecuteCommand(this->Functions[c],status);
  107. if (status.GetReturnInvoked())
  108. {
  109. inStatus.SetReturnInvoked(true);
  110. mf.RemoveFunctionBlocker(lff);
  111. return true;
  112. }
  113. if (status.GetBreakInvoked())
  114. {
  115. inStatus.SetBreakInvoked(true);
  116. mf.RemoveFunctionBlocker(lff);
  117. return true;
  118. }
  119. }
  120. }
  121. mf.RemoveFunctionBlocker(lff);
  122. return true;
  123. }
  124. }
  125. // record the command
  126. this->Functions.push_back(lff);
  127. // always return true
  128. return true;
  129. }
  130. //=========================================================================
  131. bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
  132. cmMakefile&)
  133. {
  134. if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
  135. {
  136. // if the endif has arguments, then make sure
  137. // they match the arguments of the matching if
  138. if (lff.Arguments.size() == 0 ||
  139. lff.Arguments == this->Args)
  140. {
  141. return true;
  142. }
  143. }
  144. return false;
  145. }
  146. //=========================================================================
  147. void cmIfFunctionBlocker::ScopeEnded(cmMakefile &mf)
  148. {
  149. std::string errmsg = "The end of a CMakeLists file was reached with an "
  150. "IF statement that was not closed properly.\nWithin the directory: ";
  151. errmsg += mf.GetCurrentDirectory();
  152. errmsg += "\nThe arguments are: ";
  153. for(std::vector<cmListFileArgument>::const_iterator j = this->Args.begin();
  154. j != this->Args.end(); ++j)
  155. {
  156. errmsg += (j->Quoted?"\"":"");
  157. errmsg += j->Value;
  158. errmsg += (j->Quoted?"\"":"");
  159. errmsg += " ";
  160. }
  161. cmSystemTools::Message(errmsg.c_str(), "Warning");
  162. }
  163. //=========================================================================
  164. bool cmIfCommand
  165. ::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
  166. cmExecutionStatus &)
  167. {
  168. std::string errorString;
  169. std::vector<std::string> expandedArguments;
  170. this->Makefile->ExpandArguments(args, expandedArguments);
  171. bool isTrue =
  172. cmIfCommand::IsTrue(expandedArguments,errorString,this->Makefile);
  173. if (errorString.size())
  174. {
  175. std::string err = "had incorrect arguments: ";
  176. unsigned int i;
  177. for(i =0; i < args.size(); ++i)
  178. {
  179. err += (args[i].Quoted?"\"":"");
  180. err += args[i].Value;
  181. err += (args[i].Quoted?"\"":"");
  182. err += " ";
  183. }
  184. err += "(";
  185. err += errorString;
  186. err += ").";
  187. this->SetError(err.c_str());
  188. return false;
  189. }
  190. cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
  191. // if is isn't true block the commands
  192. f->ScopeDepth = 1;
  193. f->IsBlocking = !isTrue;
  194. if (isTrue)
  195. {
  196. f->HasRun = true;
  197. }
  198. f->Args = args;
  199. this->Makefile->AddFunctionBlocker(f);
  200. return true;
  201. }
  202. namespace
  203. {
  204. //=========================================================================
  205. void IncrementArguments(std::list<std::string> &newArgs,
  206. std::list<std::string>::iterator &argP1,
  207. std::list<std::string>::iterator &argP2)
  208. {
  209. if (argP1 != newArgs.end())
  210. {
  211. argP1++;
  212. argP2 = argP1;
  213. if (argP1 != newArgs.end())
  214. {
  215. argP2++;
  216. }
  217. }
  218. }
  219. //=========================================================================
  220. // helper function to reduce code duplication
  221. void HandlePredicate(bool value, int &reducible,
  222. std::list<std::string>::iterator &arg,
  223. std::list<std::string> &newArgs,
  224. std::list<std::string>::iterator &argP1,
  225. std::list<std::string>::iterator &argP2)
  226. {
  227. if(value)
  228. {
  229. *arg = "1";
  230. }
  231. else
  232. {
  233. *arg = "0";
  234. }
  235. newArgs.erase(argP1);
  236. argP1 = arg;
  237. IncrementArguments(newArgs,argP1,argP2);
  238. reducible = 1;
  239. }
  240. //=========================================================================
  241. // helper function to reduce code duplication
  242. void HandleBinaryOp(bool value, int &reducible,
  243. std::list<std::string>::iterator &arg,
  244. std::list<std::string> &newArgs,
  245. std::list<std::string>::iterator &argP1,
  246. std::list<std::string>::iterator &argP2)
  247. {
  248. if(value)
  249. {
  250. *arg = "1";
  251. }
  252. else
  253. {
  254. *arg = "0";
  255. }
  256. newArgs.erase(argP2);
  257. newArgs.erase(argP1);
  258. argP1 = arg;
  259. IncrementArguments(newArgs,argP1,argP2);
  260. reducible = 1;
  261. }
  262. //=========================================================================
  263. enum Op { OpLess, OpEqual, OpGreater };
  264. bool HandleVersionCompare(Op op, const char* lhs_str, const char* rhs_str)
  265. {
  266. // Parse out up to 4 components.
  267. unsigned int lhs[4] = {0,0,0,0};
  268. unsigned int rhs[4] = {0,0,0,0};
  269. sscanf(lhs_str, "%u.%u.%u.%u", &lhs[0], &lhs[1], &lhs[2], &lhs[3]);
  270. sscanf(rhs_str, "%u.%u.%u.%u", &rhs[0], &rhs[1], &rhs[2], &rhs[3]);
  271. // Do component-wise comparison.
  272. for(unsigned int i=0; i < 4; ++i)
  273. {
  274. if(lhs[i] < rhs[i])
  275. {
  276. // lhs < rhs, so true if operation is LESS
  277. return op == OpLess;
  278. }
  279. else if(lhs[i] > rhs[i])
  280. {
  281. // lhs > rhs, so true if operation is GREATER
  282. return op == OpGreater;
  283. }
  284. }
  285. // lhs == rhs, so true if operation is EQUAL
  286. return op == OpEqual;
  287. }
  288. //=========================================================================
  289. // level 0 processes parenthetical expressions
  290. bool HandleLevel0(std::list<std::string> &newArgs,
  291. cmMakefile *makefile,
  292. std::string &errorString)
  293. {
  294. int reducible;
  295. do
  296. {
  297. reducible = 0;
  298. std::list<std::string>::iterator arg = newArgs.begin();
  299. while (arg != newArgs.end())
  300. {
  301. if (*arg == "(")
  302. {
  303. // search for the closing paren for this opening one
  304. std::list<std::string>::iterator argClose;
  305. argClose = arg;
  306. argClose++;
  307. unsigned int depth = 1;
  308. while (argClose != newArgs.end() && depth)
  309. {
  310. if (*argClose == "(")
  311. {
  312. depth++;
  313. }
  314. if (*argClose == ")")
  315. {
  316. depth--;
  317. }
  318. argClose++;
  319. }
  320. if (depth)
  321. {
  322. errorString = "mismatched parenthesis in condition";
  323. return false;
  324. }
  325. // store the reduced args in this vector
  326. std::vector<std::string> newArgs2;
  327. // copy to the list structure
  328. std::list<std::string>::iterator argP1 = arg;
  329. argP1++;
  330. for(; argP1 != argClose; argP1++)
  331. {
  332. newArgs2.push_back(*argP1);
  333. }
  334. newArgs2.pop_back();
  335. // now recursively invoke IsTrue to handle the values inside the
  336. // parenthetical expression
  337. bool value =
  338. cmIfCommand::IsTrue(newArgs2, errorString, makefile);
  339. if(value)
  340. {
  341. *arg = "1";
  342. }
  343. else
  344. {
  345. *arg = "0";
  346. }
  347. argP1 = arg;
  348. argP1++;
  349. // remove the now evaluated parenthetical expression
  350. newArgs.erase(argP1,argClose);
  351. }
  352. ++arg;
  353. }
  354. }
  355. while (reducible);
  356. return true;
  357. }
  358. //=========================================================================
  359. // level one handles most predicates except for NOT
  360. bool HandleLevel1(std::list<std::string> &newArgs,
  361. cmMakefile *makefile,
  362. std::string &)
  363. {
  364. int reducible;
  365. do
  366. {
  367. reducible = 0;
  368. std::list<std::string>::iterator arg = newArgs.begin();
  369. std::list<std::string>::iterator argP1;
  370. std::list<std::string>::iterator argP2;
  371. while (arg != newArgs.end())
  372. {
  373. argP1 = arg;
  374. IncrementArguments(newArgs,argP1,argP2);
  375. // does a file exist
  376. if (*arg == "EXISTS" && argP1 != newArgs.end())
  377. {
  378. HandlePredicate(
  379. cmSystemTools::FileExists((argP1)->c_str()),
  380. reducible, arg, newArgs, argP1, argP2);
  381. }
  382. // does a directory with this name exist
  383. if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end())
  384. {
  385. HandlePredicate(
  386. cmSystemTools::FileIsDirectory((argP1)->c_str()),
  387. reducible, arg, newArgs, argP1, argP2);
  388. }
  389. // is the given path an absolute path ?
  390. if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end())
  391. {
  392. HandlePredicate(
  393. cmSystemTools::FileIsFullPath((argP1)->c_str()),
  394. reducible, arg, newArgs, argP1, argP2);
  395. }
  396. // does a command exist
  397. if (*arg == "COMMAND" && argP1 != newArgs.end())
  398. {
  399. HandlePredicate(
  400. makefile->CommandExists((argP1)->c_str()),
  401. reducible, arg, newArgs, argP1, argP2);
  402. }
  403. // does a policy exist
  404. if (*arg == "POLICY" && argP1 != newArgs.end())
  405. {
  406. cmPolicies::PolicyID pid;
  407. HandlePredicate(
  408. makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid),
  409. reducible, arg, newArgs, argP1, argP2);
  410. }
  411. // does a target exist
  412. if (*arg == "TARGET" && argP1 != newArgs.end())
  413. {
  414. HandlePredicate(
  415. makefile->FindTargetToUse((argP1)->c_str())? true:false,
  416. reducible, arg, newArgs, argP1, argP2);
  417. }
  418. // is a variable defined
  419. if (*arg == "DEFINED" && argP1 != newArgs.end())
  420. {
  421. size_t argP1len = argP1->size();
  422. bool bdef = false;
  423. if(argP1len > 4 && argP1->substr(0, 4) == "ENV{" &&
  424. argP1->operator[](argP1len-1) == '}')
  425. {
  426. std::string env = argP1->substr(4, argP1len-5);
  427. bdef = cmSystemTools::GetEnv(env.c_str())?true:false;
  428. }
  429. else
  430. {
  431. bdef = makefile->IsDefinitionSet((argP1)->c_str());
  432. }
  433. HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
  434. }
  435. ++arg;
  436. }
  437. }
  438. while (reducible);
  439. return true;
  440. }
  441. //=========================================================================
  442. // level two handles most binary operations except for AND OR
  443. bool HandleLevel2(std::list<std::string> &newArgs,
  444. cmMakefile *makefile,
  445. std::string &errorString)
  446. {
  447. int reducible;
  448. const char *def;
  449. const char *def2;
  450. do
  451. {
  452. reducible = 0;
  453. std::list<std::string>::iterator arg = newArgs.begin();
  454. std::list<std::string>::iterator argP1;
  455. std::list<std::string>::iterator argP2;
  456. while (arg != newArgs.end())
  457. {
  458. argP1 = arg;
  459. IncrementArguments(newArgs,argP1,argP2);
  460. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  461. *(argP1) == "MATCHES")
  462. {
  463. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  464. const char* rex = (argP2)->c_str();
  465. cmStringCommand::ClearMatches(makefile);
  466. cmsys::RegularExpression regEntry;
  467. if ( !regEntry.compile(rex) )
  468. {
  469. cmOStringStream error;
  470. error << "Regular expression \"" << rex << "\" cannot compile";
  471. errorString = error.str();
  472. return false;
  473. }
  474. if (regEntry.find(def))
  475. {
  476. cmStringCommand::StoreMatches(makefile, regEntry);
  477. *arg = "1";
  478. }
  479. else
  480. {
  481. *arg = "0";
  482. }
  483. newArgs.erase(argP2);
  484. newArgs.erase(argP1);
  485. argP1 = arg;
  486. IncrementArguments(newArgs,argP1,argP2);
  487. reducible = 1;
  488. }
  489. if (argP1 != newArgs.end() && *arg == "MATCHES")
  490. {
  491. *arg = "0";
  492. newArgs.erase(argP1);
  493. argP1 = arg;
  494. IncrementArguments(newArgs,argP1,argP2);
  495. reducible = 1;
  496. }
  497. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  498. (*(argP1) == "LESS" || *(argP1) == "GREATER" ||
  499. *(argP1) == "EQUAL"))
  500. {
  501. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  502. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  503. double lhs;
  504. double rhs;
  505. bool result;
  506. if(sscanf(def, "%lg", &lhs) != 1 ||
  507. sscanf(def2, "%lg", &rhs) != 1)
  508. {
  509. result = false;
  510. }
  511. else if (*(argP1) == "LESS")
  512. {
  513. result = (lhs < rhs);
  514. }
  515. else if (*(argP1) == "GREATER")
  516. {
  517. result = (lhs > rhs);
  518. }
  519. else
  520. {
  521. result = (lhs == rhs);
  522. }
  523. HandleBinaryOp(result,
  524. reducible, arg, newArgs, argP1, argP2);
  525. }
  526. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  527. (*(argP1) == "STRLESS" ||
  528. *(argP1) == "STREQUAL" ||
  529. *(argP1) == "STRGREATER"))
  530. {
  531. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  532. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  533. int val = strcmp(def,def2);
  534. bool result;
  535. if (*(argP1) == "STRLESS")
  536. {
  537. result = (val < 0);
  538. }
  539. else if (*(argP1) == "STRGREATER")
  540. {
  541. result = (val > 0);
  542. }
  543. else // strequal
  544. {
  545. result = (val == 0);
  546. }
  547. HandleBinaryOp(result,
  548. reducible, arg, newArgs, argP1, argP2);
  549. }
  550. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  551. (*(argP1) == "VERSION_LESS" || *(argP1) == "VERSION_GREATER" ||
  552. *(argP1) == "VERSION_EQUAL"))
  553. {
  554. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  555. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  556. Op op = OpEqual;
  557. if(*argP1 == "VERSION_LESS")
  558. {
  559. op = OpLess;
  560. }
  561. else if(*argP1 == "VERSION_GREATER")
  562. {
  563. op = OpGreater;
  564. }
  565. bool result = HandleVersionCompare(op, def, def2);
  566. HandleBinaryOp(result,
  567. reducible, arg, newArgs, argP1, argP2);
  568. }
  569. // is file A newer than file B
  570. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  571. *(argP1) == "IS_NEWER_THAN")
  572. {
  573. int fileIsNewer=0;
  574. bool success=cmSystemTools::FileTimeCompare(arg->c_str(),
  575. (argP2)->c_str(),
  576. &fileIsNewer);
  577. HandleBinaryOp(
  578. (success==false || fileIsNewer==1 || fileIsNewer==0),
  579. reducible, arg, newArgs, argP1, argP2);
  580. }
  581. ++arg;
  582. }
  583. }
  584. while (reducible);
  585. return true;
  586. }
  587. //=========================================================================
  588. // level 3 handles NOT
  589. bool HandleLevel3(std::list<std::string> &newArgs,
  590. cmMakefile *makefile,
  591. std::string &)
  592. {
  593. int reducible;
  594. const char *def;
  595. do
  596. {
  597. reducible = 0;
  598. std::list<std::string>::iterator arg = newArgs.begin();
  599. std::list<std::string>::iterator argP1;
  600. std::list<std::string>::iterator argP2;
  601. while (arg != newArgs.end())
  602. {
  603. argP1 = arg;
  604. IncrementArguments(newArgs,argP1,argP2);
  605. if (argP1 != newArgs.end() && *arg == "NOT")
  606. {
  607. def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
  608. HandlePredicate(cmSystemTools::IsOff(def),
  609. reducible, arg, newArgs, argP1, argP2);
  610. }
  611. ++arg;
  612. }
  613. }
  614. while (reducible);
  615. return true;
  616. }
  617. //=========================================================================
  618. // level 4 handles AND OR
  619. bool HandleLevel4(std::list<std::string> &newArgs,
  620. cmMakefile *makefile,
  621. std::string &)
  622. {
  623. int reducible;
  624. const char *def;
  625. const char *def2;
  626. do
  627. {
  628. reducible = 0;
  629. std::list<std::string>::iterator arg = newArgs.begin();
  630. std::list<std::string>::iterator argP1;
  631. std::list<std::string>::iterator argP2;
  632. while (arg != newArgs.end())
  633. {
  634. argP1 = arg;
  635. IncrementArguments(newArgs,argP1,argP2);
  636. if (argP1 != newArgs.end() && *(argP1) == "AND" &&
  637. argP2 != newArgs.end())
  638. {
  639. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  640. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  641. HandleBinaryOp(
  642. !(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2)),
  643. reducible, arg, newArgs, argP1, argP2);
  644. }
  645. if (argP1 != newArgs.end() && *(argP1) == "OR" &&
  646. argP2 != newArgs.end())
  647. {
  648. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  649. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  650. HandleBinaryOp(
  651. !(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2)),
  652. reducible, arg, newArgs, argP1, argP2);
  653. }
  654. ++arg;
  655. }
  656. }
  657. while (reducible);
  658. return true;
  659. }
  660. }
  661. //=========================================================================
  662. // order of operations,
  663. // 1. ( ) -- parenthetical groups
  664. // 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
  665. // 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
  666. // 4. NOT
  667. // 5. AND OR
  668. //
  669. // There is an issue on whether the arguments should be values of references,
  670. // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
  671. // or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
  672. // EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
  673. // take numeric values or variable names. STRLESS and STRGREATER take
  674. // variable names but if the variable name is not found it will use the name
  675. // directly. AND OR take variables or the values 0 or 1.
  676. bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
  677. std::string &errorString, cmMakefile *makefile)
  678. {
  679. const char *def;
  680. errorString = "";
  681. // handle empty invocation
  682. if (args.size() < 1)
  683. {
  684. return false;
  685. }
  686. // store the reduced args in this vector
  687. std::list<std::string> newArgs;
  688. // copy to the list structure
  689. for(unsigned int i = 0; i < args.size(); ++i)
  690. {
  691. newArgs.push_back(args[i]);
  692. }
  693. // now loop through the arguments and see if we can reduce any of them
  694. // we do this multiple times. Once for each level of precedence
  695. if (!HandleLevel0(newArgs, makefile, errorString)) // parens
  696. {
  697. return false;
  698. }
  699. if (!HandleLevel1(newArgs, makefile, errorString)) //predicates
  700. {
  701. return false;
  702. }
  703. if (!HandleLevel2(newArgs, makefile, errorString)) // binary ops
  704. {
  705. return false;
  706. }
  707. if (!HandleLevel3(newArgs, makefile, errorString)) // NOT
  708. {
  709. return false;
  710. }
  711. if (!HandleLevel4(newArgs, makefile, errorString)) // AND OR
  712. {
  713. return false;
  714. }
  715. // now at the end there should only be one argument left
  716. if (newArgs.size() == 1)
  717. {
  718. if (*newArgs.begin() == "0")
  719. {
  720. return false;
  721. }
  722. if (*newArgs.begin() == "1")
  723. {
  724. return true;
  725. }
  726. def = makefile->GetDefinition(args[0].c_str());
  727. if(cmSystemTools::IsOff(def))
  728. {
  729. return false;
  730. }
  731. }
  732. else
  733. {
  734. errorString = "Unknown arguments specified";
  735. return false;
  736. }
  737. return true;
  738. }
  739. //=========================================================================
  740. const char* cmIfCommand::GetVariableOrString(const char* str,
  741. const cmMakefile* mf)
  742. {
  743. const char* def = mf->GetDefinition(str);
  744. if(!def)
  745. {
  746. def = str;
  747. }
  748. return def;
  749. }
  750. //=========================================================================
  751. const char* cmIfCommand::GetVariableOrNumber(const char* str,
  752. const cmMakefile* mf)
  753. {
  754. const char* def = mf->GetDefinition(str);
  755. if(!def)
  756. {
  757. if (atoi(str))
  758. {
  759. def = str;
  760. }
  761. }
  762. return def;
  763. }